1 /*******************************************************************************
2 * pvengine.cpp
3 *
4 * This file implements Windows specific routines, WinMain, and message loops.
5 *
6 * Primary author: Christopher J. Cason.
7 *
8 * ---------------------------------------------------------------------------
9 * Persistence of Vision Ray Tracer ('POV-Ray') version 3.7.
10 * Copyright 1991-2013 Persistence of Vision Raytracer Pty. Ltd.
11 *
12 * POV-Ray is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Affero General Public License as
14 * published by the Free Software Foundation, either version 3 of the
15 * License, or (at your option) any later version.
16 *
17 * POV-Ray is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Affero General Public License for more details.
21 *
22 * You should have received a copy of the GNU Affero General Public License
23 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 * ---------------------------------------------------------------------------
25 * POV-Ray is based on the popular DKB raytracer version 2.12.
26 * DKBTrace was originally written by David K. Buck.
27 * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
28 * ---------------------------------------------------------------------------
29 * $File: //depot/public/povray/3.x/windows/pvengine.cpp $
30 * $Revision: #1 $
31 * $Change: 6069 $
32 * $DateTime: 2013/11/06 11:59:40 $
33 * $Author: chrisc $
34 *******************************************************************************/
35
36 /*****************************************************************************/
37 /* NOTICE */
38 /* */
39 /* Much of this source code (all of pvengine.exe) should be considered on */
40 /* its last legs. The base code was originally written back in early 1995 */
41 /* (with some of the code even predating that), and targeted at Win32s under */
42 /* Windows 3.1. An additional constraint was a desire for the code to be */
43 /* able to be compiled on a DEC Alpha under NT for the Alpha using only a */
44 /* 'C' compiler, and for it to be able to run with or without the editor. */
45 /* */
46 /* With the introduction of VFE in version 3.7, creating a new UI for POVWIN */
47 /* should be a lot less painful as almost all of the bindings with the core */
48 /* POV-Ray renderer have been abstracted into the above class library. */
49 /* */
50 /*****************************************************************************/
51
52 #define POVWIN_FILE
53 #define _WIN32_IE COMMONCTRL_VERSION
54
55 #if !defined( __BORLANDC__ ) && !defined( __DMC__ ) && !defined( __MINGW32__ )
56 #pragma comment(lib, "htmlhelp")
57 #pragma comment(lib, "winmm")
58 #endif
59
60 #define _CRT_RAND_S
61 #define PSAPI_VERSION 1
62 #pragma comment(lib, "psapi")
63
64 #include <windows.h>
65 #include <htmlhelp.h>
66 #include <shellapi.h>
67 #include <shlobj.h>
68 #include <shlwapi.h>
69 #include <mmsystem.h>
70 #include <commdlg.h>
71 #include <commctrl.h>
72 #include <crtdbg.h>
73 #include <psapi.h>
74 #include <dbghelp.h>
75
76 // #define DEVELOPMENT
77
78 #include <stdlib.h>
79 #include <stdio.h>
80 #include <tchar.h>
81 #include "pvengine.h"
82 #include "resource.h"
83 #include "pvdialog.h"
84 #include "pvguiext.h"
85 #include "pvedit.h"
86 #include "backend/control/benchmark.h"
87 #include "pvdisplay.h"
88 #include "syspovprotofrontend.h"
89 #include "povray.h"
90
91 #ifdef RTR_SUPPORT
92 #include "rtrsupport.h"
93 #endif
94
95 #if defined(USE_AVX_FMA4_FOR_NOISE)
96 #include "backend/texture/avxfma4check.h"
97 #endif
98
99 // this must be the last file included
100 #include "syspovdebug.h"
101
102 typedef HRESULT (CALLBACK* DLLGETVERSIONPROC) (DLLVERSIONINFO *);
103 typedef DWORD __stdcall shCopyType (HKEY, LPCTSTR, HKEY, DWORD) ;
104
105 #ifndef SM_CMONITORS
106 #define SM_XVIRTUALSCREEN 76
107 #define SM_YVIRTUALSCREEN 77
108 #define SM_CXVIRTUALSCREEN 78
109 #define SM_CYVIRTUALSCREEN 79
110 #define SM_CMONITORS 80
111 #endif
112
113 #ifndef PROCESS_MODE_BACKGROUND_BEGIN
114 #define PROCESS_MODE_BACKGROUND_BEGIN 0x00100000
115 #define PROCESS_MODE_BACKGROUND_END 0x00200000
116 #endif
117
118 #define CONFIRM_STOP_THRESHOLD 900
119
120 typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType,
121 CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
122 CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
123 CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam
124 );
125
126 char *WriteDump(struct _EXCEPTION_POINTERS *pExceptionInfo, bool full, long timestamp);
127
128 namespace pov_frontend
129 {
130 extern shared_ptr<Display> gDisplay;
131 }
132
133 namespace vfePlatform
134 {
135 extern bool GetCPUCount(unsigned int *TotAvailLogical, unsigned int *TotAvailCore, unsigned int *PhysicalNum);
136 }
137
138 using namespace pov;
139 using namespace pov_frontend;
140
141 void GenerateDumpMeta(bool brief);
142
143 namespace povwin
144 {
145
146 typedef struct
147 {
148 int id ;
149 HWND hwnd ;
150 SIZE size ;
151 } StatusPanelItem ;
152
153 bool rendering ;
154 bool stop_rendering ;
155 bool rendersleep ;
156 bool render_cooperate = false ;
157 bool InFrontend = false ;
158 bool ErrorNotified ;
159 bool ErrorOccurred ;
160 bool HideRenderWithMain ;
161 bool UseAlpha;
162 bool IsExpired;
163 bool BackendFailedFlag = false;
164 bool PreventSleep = true;
165 char DumpMeta[65536];
166 string ErrorMessage ;
167 string ErrorFilename ;
168 unsigned ErrorLine ;
169 unsigned ErrorCol ;
170 unsigned render_priority = CM_RENDERPRIORITY_NORMAL ;
171 unsigned Duty_Cycle = 9 ;
172 unsigned renderwin_8bits ;
173
174 extern int renderwin_xoffset ;
175 extern int renderwin_yoffset ;
176 extern int renderwin_left ;
177 extern int renderwin_top ;
178 extern char PovLegacyRenderWinClass [] ;
179 extern unsigned renderwin_max_width ;
180 extern unsigned renderwin_max_height ;
181 extern unsigned renderwin_flags ;
182 extern bool MakeRenderwinActive ;
183
184 int render_bitmap_depth ;
185 unsigned render_width ;
186 unsigned render_height ;
187
188 int alert_sound ;
189 int run_count ;
190 int render_anim_count ;
191 int argc ;
192 int io_restrictions ;
193 int tb_combo_sel ;
194 int povray_return_code ;
195 int PerformanceScale = 1 ;
196 int seconds_for_last_line = -1 ;
197 int delay_next_status ;
198 int screen_origin_x ;
199 int screen_origin_y ;
200 int virtual_screen_width ;
201 int virtual_screen_height ;
202 int LastRenderPercentage ;
203 int renderwin_transparency ;
204 int cb_expect_selchange ;
205 char command_line [_MAX_PATH * 3] ;
206 char old_command_line [_MAX_PATH * 3] ;
207 char *argv [MAX_ARGV] ;
208 char source_file_name [_MAX_PATH] ;
209 char modulePath [_MAX_PATH] ;
210 char engineHelpPath [_MAX_PATH] ;
211 char lastRenderName [_MAX_PATH] ;
212 char lastBitmapName [_MAX_PATH] ;
213 char lastRenderPath [_MAX_PATH] ;
214 char lastBitmapPath [_MAX_PATH] ;
215 char lastQueuePath [_MAX_PATH] ;
216 char lastSecondaryIniFilePath [_MAX_PATH] ;
217 char DefaultRenderIniFileName [_MAX_PATH] ;
218 char SecondaryRenderIniFileName [_MAX_PATH] ;
219 char SecondaryRenderIniFileSection [64] ;
220 char background_file [_MAX_PATH] ;
221 char EngineIniFileName[_MAX_PATH] ;
222 char BinariesPath [_MAX_PATH] ;
223 char DocumentsPath [_MAX_PATH] ;
224 char LastInferredHome [_MAX_PATH] ;
225 char ToolIniFileName [_MAX_PATH] ;
226 char tool_commands [MAX_TOOLCMD] [MAX_TOOLCMDTEXT] ;
227 char tool_help [MAX_TOOLCMD] [MAX_TOOLHELPTEXT] ;
228 char requested_render_file [_MAX_PATH] ;
229 char RegionStr [128] ;
230 char TempRegionStr [128] ;
231 char demo_file_name [_MAX_PATH] ;
232 char demo_ini_name [_MAX_PATH] ;
233 char status_buffer [1024] ;
234 char render_complete_sound [_MAX_PATH] ;
235 char parse_error_sound [_MAX_PATH] ;
236 char render_error_sound [_MAX_PATH] ;
237 char FontPath [_MAX_PATH] ;
238 char *EditDLLPath ;
239 bool render_complete_sound_enabled ;
240 bool parse_error_sound_enabled ;
241 bool render_error_sound_enabled ;
242 bool alert_on_completion ;
243 bool save_settings ;
244 bool IsW95UserInterface = true;
245 bool IsW98 ;
246 bool IsWNT ;
247 bool IsW2k ;
248 bool IsWXP ;
249 bool IsVista ;
250 bool running_demo ;
251 bool running_benchmark ;
252 bool benchmark_multithread ;
253 bool fast_scroll ;
254 bool no_shellout_wait ;
255 bool tile_background = false ;
256 bool debugging ;
257 bool no_palette_warn ;
258 bool render_lock_up ;
259 bool RenderwinIsChild = true ;
260 bool demo_mode ;
261 bool benchmark_mode;
262 bool ignore_auto_ini ;
263 bool newVersion ;
264 bool exit_after_render ;
265 bool system_noactive ;
266 bool one_instance = true ;
267 bool run_renderer ;
268 bool use_toolbar = true ;
269 bool use_tooltips = true ;
270 bool use_editors = true ;
271 bool editors_enabled = true;
272 bool resizing ;
273 bool drop_to_editor ;
274 bool restore_command_line ;
275 bool render_requested ;
276 bool render_auto_close ;
277 bool noexec ;
278 bool ExtensionsEnabled = true ;
279 bool use_taskbar = true ;
280 bool main_window_hidden ;
281 bool about_showing ;
282 bool NoRestore ;
283 bool IsComCtl5 = false ;
284 bool IsComCtl6 = false ;
285 bool allow_rw_source ;
286 bool no_shell_outs = true ;
287 bool hide_newuser_help ;
288 bool info_render_complete = false ;
289 bool no_status_output = false ;
290 bool temp_render_region = false ;
291 bool rendering_insert_menu = false ;
292 bool was_insert_render = false ;
293 bool rendering_animation = false ;
294 bool preserve_bitmap = false ;
295 bool first_frame = false ;
296 bool check_new_version ;
297 bool check_news ;
298 bool send_system_info ;
299 bool homeInferred = false ;
300 bool editSettingsCopied = false ;
301 bool FreshInstall = false;
302 bool output_to_file ;
303 bool UpdateCheckDone = false ;
304 bool AutoAppendPaths ;
305 HWND toolbar_window ;
306 HWND aux_toolbar_window ;
307 HWND window_list [MAX_WINDOWS] ;
308 HWND toolbar_combobox ;
309 HWND rebar_window ;
310 HWND StatusWindow ;
311 HWND StatusTooltip ;
312 HWND toolbar_cmdline ;
313 HWND tab_window ;
314 HICON ourIcon ;
315 HICON renderIcon ;
316 HFONT about_font ;
317 HANDLE hMainThread ;
318 string InputFileName ;
319 time_t SecondCountStart ;
320 time_t quit ;
321 HBITMAP hBmpBackground ;
322 HBITMAP hBmpRendering ;
323 HBITMAP hBmpIcon ;
324 HBITMAP hBmpAbout ;
325 __int64 PerformanceFrequency ;
326 __int64 PerformanceCounter1 ;
327 __int64 PerformanceCounter2 ;
328 __int64 KernelTimeStart ;
329 __int64 KernelTimeEnd ;
330 __int64 UserTimeStart ;
331 __int64 UserTimeEnd ;
332 __int64 KernelTimeTotal ;
333 __int64 UserTimeTotal ;
334 __int64 CPUTimeTotal ;
335 clock_t ClockTimeStart ;
336 clock_t ClockTimeEnd ;
337 clock_t ClockTimeTotal ;
338 clock_t SleepTimeStart ;
339 clock_t SleepTimeEnd ;
340 clock_t SleepTimeTotal ;
341 unsigned class_registered = 0 ;
342 unsigned currentX = 0 ;
343 unsigned currentY = 0 ;
344 unsigned screen_width ;
345 unsigned screen_height ;
346 unsigned screen_depth ;
347 unsigned background_width ;
348 unsigned background_height ;
349 unsigned seconds = 0 ;
350 unsigned toolheight = 0 ;
351 unsigned statusheight = 0 ;
352 unsigned on_completion = CM_COMPLETION_NOTHING ;
353 unsigned window_count = 0 ;
354 unsigned ThreadCount = 2 ;
355 unsigned NumberOfCPUs ;
356 unsigned NumLogicalCPUs ;
357 unsigned NumCPUCores ;
358 unsigned NumPhysicalCPUs ;
359 HPALETTE hPalApp ;
360 HPALETTE hPalBitmap ;
361 COLORREF background_colour ;
362 COLORREF text_colours [3] ;
363 COLORREF custom_colours [16] ;
364 COLORREF background_shade = RGB (1, 1, 1) ;
365 HINSTANCE hInstance ;
366 HH_AKLINK hh_aklink ;
367 OSVERSIONINFO version_info ;
368 StatusPanelItem StatusPanelItems [IDC_STATUS_ID_LAST + 1] ;
369 CRITICAL_SECTION critical_section ;
370
371 // key is the name of an included file (all lower case).
372 // content is the name of the most recent rendered file that caused it to be included.
373 std::map<string, string> IncludeToSourceMap;
374 std::map<string, bool> IncludeAlternateDecisionMap;
375
376 char queued_files [MAX_QUEUE] [_MAX_PATH] ;
377 char dir [_MAX_PATH] ;
378 unsigned queued_file_count = 0 ;
379 unsigned auto_render = true ;
380 unsigned timer_id ;
381 unsigned about_timer_id ;
382 unsigned timer_ticks;
383
384 unsigned panel_size ;
385
386 char PovMainWinClass [] = CLASSNAMEPREFIX "MainWinClass" ;
387 unsigned mainwin_xpos ;
388 unsigned mainwin_ypos ;
389 HWND main_window ;
390 HWND message_window ;
391 WINDOWPLACEMENT mainwin_placement ;
392
393 char PovAboutWinClass [] = CLASSNAMEPREFIX "AboutWinClass" ;
394 HWND about_window ;
395 HWND about_buttons [3] ;
396 WNDPROC about_button_wndproc ;
397 unsigned about_width ;
398 unsigned about_height ;
399 HPALETTE about_palette ;
400
401 HWND statuspanel ;
402
403 char PovMessageWinClass [] = CLASSNAMEPREFIX "MessageWinClass" ;
404
405 #define NUM_ABOUT_LINKS 7
406 RECT AboutLinks[NUM_ABOUT_LINKS] =
407 {
408 { 23, 14, 188, 87 },
409 { 104, 397, 184, 409 },
410 { 185, 397, 262, 409 },
411 { 263, 397, 370, 409 },
412 { 371, 397, 480, 409 },
413 { 481, 397, 560, 409 },
414 { 32, 411, 154, 423 }
415 };
416 char *AboutURLs[NUM_ABOUT_LINKS] =
417 {
418 "http://www.povray.org/",
419 "http://www.digicert.com/",
420 "http://ntplx.net/",
421 "http://opensourcelaw.biz/",
422 "http://www.perforce.com/",
423 "http://softwarefreedom.org/",
424 "http://softwarefreedom.org/"
425 };
426
427 bool handle_main_command (WPARAM wParam, LPARAM lParam) ;
428 void SetStatusPanelItemText (int id, LPCSTR format, ...) ;
429 void ShowAboutBox (void);
430
431 extern int message_xchar ;
432 extern int message_ychar ;
433 extern int message_scroll_pos_x ;
434 extern int message_scroll_pos_y ;
435 extern int top_message_row ;
436 extern int message_count ;
437 extern int message_cols ;
438 extern int message_rows ;
439 extern int listbox_xchar ;
440 extern int listbox_ychar ;
441 extern int EditFileCount ;
442 extern int message_output_x ;
443 extern char message_font_name [256] ;
444 extern char *EditFiles [] ;
445 extern bool ListenMode ;
446 extern bool keep_messages ;
447 extern bool MenuBarDraw ;
448 extern bool TrackMem;
449 extern __int64 PeakMem;
450 extern unsigned message_font_size ;
451 extern unsigned message_font_weight ;
452 extern HFONT message_font ;
453 extern HFONT tab_font ;
454 extern HMENU hMenuBar ;
455 extern HMENU hMainMenu ;
456 extern HMENU hPopupMenus ;
457 extern HMENU hVidcapMenu ;
458 extern HACCEL hAccelerators ;
459 extern HINSTANCE hLibPovEdit ;
460
461 #define MAX_INSERT_MENU_SECTIONS 8192
462
463 typedef std::vector<int> InsMenuSecList;
464
465 int InsertMenuSection;
466 bool StartInsertRender;
467 InsMenuSecList InsertMenuSections;
468
469 typedef struct
470 {
471 WORD wVirtkey ;
472 int iMessage ;
473 WORD wRequest ;
474 } SCROLLKEYS ;
475
476 SCROLLKEYS key2scroll [] =
477 {
478 { VK_END, WM_VSCROLL, SB_BOTTOM },
479 { VK_PRIOR, WM_VSCROLL, SB_PAGEUP },
480 { VK_NEXT, WM_VSCROLL, SB_PAGEDOWN },
481 { VK_UP, WM_VSCROLL, SB_LINEUP },
482 { VK_DOWN, WM_VSCROLL, SB_LINEDOWN },
483 { VK_LEFT, WM_HSCROLL, SB_PAGEUP },
484 { VK_RIGHT, WM_HSCROLL, SB_PAGEDOWN },
485 { -1, -1, -1 }
486 } ;
487
StripFilePath(const string & str)488 string StripFilePath (const string& str)
489 {
490 string::size_type pos = str.find_last_of ("\\/") ;
491 if (pos == string::npos)
492 return (str) ;
493 return string (str, pos + 1) ;
494 }
495
StripPathComponent(char * path,int number)496 bool StripPathComponent (char *path, int number)
497 {
498 if (number > 1)
499 if (!StripPathComponent (path, number - 1))
500 return (false) ;
501 char *s = path + strlen (path) - 1 ;
502 if (isPathSeparator(*s))
503 *s-- = '\0' ;
504 while (s > path && !isPathSeparator(*s))
505 s-- ;
506 *s = '\0' ;
507 return (path [0] != '\0') ;
508 }
509
debug_output(const char * format,...)510 void debug_output (const char *format, ...)
511 {
512 char str [2048] ;
513 va_list arg_ptr ;
514 FILE *f ;
515
516 if (format == NULL)
517 {
518 _unlink ("c:\\temp\\povdebug.txt") ;
519 return ;
520 }
521
522 va_start (arg_ptr, format) ;
523 vsprintf (str, format, arg_ptr) ;
524 va_end (arg_ptr) ;
525 OutputDebugString (str) ;
526
527 if ((f = fopen ("c:\\temp\\povdebug.txt", "a+t")) != NULL)
528 {
529 fprintf (f, sizeof(time_t) == 4 ? "%u: %s" : "%I64u: %s", time (NULL), str) ;
530
531 fclose (f) ;
532 }
533 }
534
535 // this function is declared in syspovconfig.h ... use pov::WIN32_DEBUG_OUTPUT() from
536 // anywhere in the POV-Ray source, core or otherwise
WIN32_DEBUG_OUTPUT(const char * format,...)537 void WIN32_DEBUG_OUTPUT (const char *format,...)
538 {
539 char str [2048] ;
540 va_list arg_ptr ;
541
542 sprintf (str, "%5d ", GetCurrentThreadId());
543 va_start (arg_ptr, format) ;
544 vsprintf (str + 6, format, arg_ptr) ;
545 va_end (arg_ptr) ;
546 OutputDebugString (str) ;
547 }
548
549 // this function is declared in syspovconfig.h ... use pov::WIN32_DEBUG_FILE_OUTPUT() from
550 // anywhere in the POV-Ray source, core or otherwise. it's also thread-safe.
WIN32_DEBUG_FILE_OUTPUT(const char * format,...)551 void WIN32_DEBUG_FILE_OUTPUT (const char *format,...)
552 {
553 va_list arg_ptr ;
554 static FILE *f ;
555 static boost::mutex mtx;
556
557 if (format == NULL)
558 {
559 if (f != NULL)
560 {
561 fclose (f) ;
562 f = NULL ;
563 }
564 return ;
565 }
566
567 if (f == NULL)
568 {
569 f = fopen ("c:\\temp\\povdebug.txt", "at") ;
570 if (f == NULL)
571 return ;
572 }
573
574 boost::mutex::scoped_lock l(mtx);
575 fprintf (f, "%u [%d]: ", GetTickCount (), GetCurrentThreadId ()) ;
576 va_start (arg_ptr, format) ;
577 vfprintf (f, format, arg_ptr) ;
578 va_end (arg_ptr) ;
579 fflush (f);
580 }
581
SetCaption(LPCSTR str)582 void SetCaption (LPCSTR str)
583 {
584 char buffer [1024] ;
585 static char lastStr [1024] ;
586 vfeSession& Session (GetSession());
587
588 if (str != NULL)
589 strcpy (lastStr, str) ;
590 else
591 str = lastStr ;
592
593 if (Session.BackendFailed())
594 {
595 SetWindowText (main_window, "Backend Failed") ;
596 return;
597 }
598
599 #ifndef DEVELOPMENT
600 if (Session.GetBackendState() == kRendering && InputFileName.size () > 0)
601 {
602 string filename = StripFilePath (InputFileName) ;
603 if (strstr (str, filename.c_str ()) != NULL)
604 {
605 // if the filename is in the caption already, we're probably rendering
606 // the current editor file (exception: if a file with the same name but
607 // a different path is being viewed).
608 sprintf (buffer, "%s [%s %d%%]", str, Session.GetBackendStateName(), Session.GetPercentComplete()) ;
609 }
610 else
611 {
612 // the render file name is not in the caption: in that case we are
613 // probably viewing another file or the message window.
614 sprintf (buffer, "%s [Rendering %s: %d%%]", str, filename.c_str (), Session.GetPercentComplete()) ;
615 }
616 }
617 else
618 sprintf (buffer, "%s [%s]", str, Session.GetBackendStateName ()) ;
619 SetWindowText (main_window, buffer) ;
620 #else
621 if (Session.GetBackendState() == kRendering && InputFileName.size () > 0)
622 {
623 string filename = StripFilePath (InputFileName) ;
624 if (strstr (str, filename.c_str ()) != NULL)
625 {
626 // if the filename is in the caption already, we're probably rendering
627 // the current editor file (exception: if a file with the same name but
628 // a different path is being viewed).
629 sprintf (buffer, CAPTIONPREFIX " %s [%s %d%%]", str, Session.GetBackendStateName(), Session.GetPercentComplete()) ;
630 }
631 else
632 {
633 // the render file name is not in the caption: in that case we are
634 // probably viewing another file or the message window.
635 sprintf (buffer, CAPTIONPREFIX " %s [Rendering %s:%d%%]", str, filename.c_str (), Session.GetPercentComplete()) ;
636 }
637 }
638 else
639 sprintf (buffer, CAPTIONPREFIX " %s [%s]", str, Session.GetBackendStateName()) ;
640 SetWindowText (main_window, buffer) ;
641 #endif
642 }
643
644 // returned value is in microseconds
GetCPUTime(bool Kernel=true,bool User=true)645 __int64 GetCPUTime (bool Kernel = true, bool User = true)
646 {
647 __int64 kt ;
648 __int64 ut ;
649 __int64 total = 0 ;
650 FILETIME ct ;
651 FILETIME et ;
652
653 if (IsWNT)
654 {
655 if (!GetProcessTimes (GetCurrentProcess (), &ct, &et, (FILETIME *) &kt, (FILETIME *) &ut))
656 {
657 assert (false) ;
658 return (0) ;
659 }
660 if (Kernel)
661 total += kt ;
662 if (User)
663 total += ut ;
664 return (total / 10) ;
665 }
666 else
667 {
668 // have to simulate the results for now
669 // TODO: handle pause time
670 ut = clock () ;
671 if (User)
672 total += ut * 1000 ;
673 return (total) ;
674 }
675 }
676
PPS_String(unsigned pixels,unsigned renderseconds)677 char *PPS_String (unsigned pixels, unsigned renderseconds)
678 {
679 static char str [128] ;
680
681 if (rendersleep)
682 return ("PAUSED") ;
683
684 if (renderseconds == 0)
685 return ("??? PPS") ;
686
687 if (pixels / renderseconds < 5)
688 {
689 if (pixels * 60 / renderseconds < 5)
690 sprintf (str, "%u PPH", pixels * 3600 / renderseconds) ;
691 else
692 sprintf (str, "%u PPM", pixels * 60 / renderseconds) ;
693 }
694 else
695 sprintf (str, "%u PPS", pixels / renderseconds) ;
696 return (str) ;
697 }
698
PrintRenderTimes(int Finished,int NormalCompletion)699 void PrintRenderTimes (int Finished, int NormalCompletion)
700 {
701 int PixelsRendered = GetSession().GetPixelsRendered();
702 unsigned STT = SleepTimeTotal ;
703
704 if (rendersleep)
705 {
706 SleepTimeEnd = clock () ;
707 if (Finished)
708 {
709 SleepTimeTotal += SleepTimeEnd - SleepTimeStart ;
710 STT = SleepTimeTotal ;
711 rendersleep = false ;
712 }
713 else
714 STT += SleepTimeEnd - SleepTimeStart ;
715 }
716 KernelTimeEnd = GetCPUTime (true, false) ;
717 UserTimeEnd = GetCPUTime (false, true) ;
718 KernelTimeTotal = KernelTimeEnd - KernelTimeStart ;
719 UserTimeTotal = UserTimeEnd - UserTimeStart ;
720 CPUTimeTotal = UserTimeTotal + KernelTimeTotal ;
721 ClockTimeEnd = clock () ;
722 ClockTimeTotal = ClockTimeEnd - ClockTimeStart - STT ;
723 if (ClockTimeTotal >= CLOCKS_PER_SEC)
724 status_printf (StatusPPS, PPS_String (PixelsRendered, ClockTimeTotal / CLOCKS_PER_SEC)) ;
725 say_status_message (StatusRendertime, get_elapsed_time (ClockTimeTotal / CLOCKS_PER_SEC)) ;
726 if (IsWNT != 0 && Finished != 0)
727 {
728 message_printf ("CPU time used: kernel %.02f seconds, user %.02f seconds, total %.02f seconds.\n",
729 KernelTimeTotal / 1000000.0, UserTimeTotal / 1000000.0, CPUTimeTotal / 1000000.0) ;
730 message_printf ("Elapsed time %.02f seconds", (double) ClockTimeTotal / CLOCKS_PER_SEC) ;
731 if (NumberOfCPUs > 1 && ThreadCount > 1)
732 {
733 POV_ULONG cputotal = CPUTimeTotal * CLOCKS_PER_SEC / 1000000 ;
734 if (cputotal > ClockTimeTotal * 10 / 9)
735 message_printf (", CPU vs elapsed time ratio %.02f", (double) cputotal / ClockTimeTotal) ;
736 }
737 message_printf (".\n") ;
738 if (PixelsRendered > 0 && CPUTimeTotal > 0 && NormalCompletion)
739 {
740 message_printf ("Render averaged %.02f PPS (%.02f PPS CPU time) over %u pixels.\n",
741 (double) PixelsRendered * CLOCKS_PER_SEC / ClockTimeTotal, (double) PixelsRendered * 1000000 / CPUTimeTotal, PixelsRendered) ;
742 message_printf ("----------------------------------------------------------------------------\n") ;
743 #ifndef _DEBUG
744 char str [2048] ;
745 if (running_benchmark)
746 {
747 char *s = str;
748 s += sprintf(str, "CPU time used: kernel %.02f seconds, user %.02f seconds, total %.02f seconds.\n",
749 KernelTimeTotal / 1000000.0, UserTimeTotal / 1000000.0, CPUTimeTotal / 1000000.0) ;
750 s += sprintf(s, "Elapsed time %.02f seconds", (double) ClockTimeTotal / CLOCKS_PER_SEC) ;
751 if (NumberOfCPUs > 1 && ThreadCount > 1)
752 {
753 POV_ULONG cputotal = CPUTimeTotal * CLOCKS_PER_SEC / 1000000 ;
754 if (cputotal > ClockTimeTotal * 10 / 9)
755 s += sprintf(s, ", CPU vs elapsed time ratio %.02f", (double) cputotal / ClockTimeTotal) ;
756 }
757 s += sprintf(s, ".\n") ;
758 s += sprintf (s, "Render averaged %.02f PPS (%.02f PPS CPU time) over %u pixels using %u thread(s).\n",
759 (double) PixelsRendered * CLOCKS_PER_SEC / ClockTimeTotal, (double) PixelsRendered * 1000000 / CPUTimeTotal, PixelsRendered, ThreadCount) ;
760 copy_text_to_clipboard(str);
761 if (benchmark_mode)
762 {
763 // special case: we are running the benchmark because of a command-line request.
764 char fn[_MAX_PATH];
765 char ts[256];
766 time_t t = time(NULL);
767
768 strftime(ts, sizeof(ts), "%Y%m%d.%H%M%S", gmtime(&t));
769 sprintf(fn, "%sbenchmark-%s.txt", DocumentsPath, ts);
770 FILE *f = fopen(fn, "wt");
771 if (f != NULL)
772 {
773 int n = Get_Benchmark_Version();
774
775 fprintf(f, "%s", str);
776 strftime(str, sizeof(str), "%#c", gmtime(&t));
777 fprintf(f, "\nRender of benchmark version %x.%02x completed at %s UTC.\n", n / 256, n % 256, str);
778 fprintf(f, "----------------------------------------------------------------------------\n");
779 GenerateDumpMeta(true);
780 fwrite(DumpMeta, strlen(DumpMeta), 1, f);
781 fprintf(f, "povversion=%s\n", POV_RAY_VERSION) ;
782 fprintf(f, "compilerversion=%s\n", COMPILER_VER) ;
783 fprintf(f, "platformversion=%s\n", PVENGINE_VER) ;
784 fclose(f);
785 }
786 }
787 else
788 {
789 strcat(str, "\nThese results have been placed in the clipboard.\n");
790 MessageBox (main_window, str, "Benchmark Complete.", MB_OK) ;
791 }
792 }
793 #endif
794 }
795 else
796 message_printf ("----------------------------------------------------------------------------\n") ;
797 }
798 }
799
OkToStopRendering(void)800 bool OkToStopRendering (void)
801 {
802 if (GetSession().BackendFailed())
803 return (true);
804 if (time (NULL) - SecondCountStart < CONFIRM_STOP_THRESHOLD)
805 return (true) ;
806 if (GetSession().GetRealTimeRaytracing() == true)
807 return (true);
808 if (MessageBox (main_window, "You've been running this render for quite a while - really cancel ?", "Stop rendering ?", MB_ICONQUESTION | MB_YESNO) == IDYES)
809 return (true) ;
810 return (false) ;
811 }
812
menuhelp(UINT idCommand)813 void menuhelp (UINT idCommand)
814 {
815 switch (idCommand)
816 {
817 case CM_FILEMENUHELP :
818 hh_aklink.pszKeywords = "File Menu" ;
819 break ;
820
821 case CM_EDITMENUHELP :
822 hh_aklink.pszKeywords = "Edit Menu" ;
823 break ;
824
825 case CM_SEARCHMENUHELP :
826 hh_aklink.pszKeywords = "Search Menu" ;
827 break ;
828
829 case CM_TEXTMENUHELP :
830 hh_aklink.pszKeywords = "Text Menu" ;
831 break ;
832
833 case CM_EDITORMENUHELP :
834 hh_aklink.pszKeywords = "Editor Menu" ;
835 break ;
836
837 case CM_RENDERMENUHELP :
838 hh_aklink.pszKeywords = "Render Menu" ;
839 break ;
840
841 case CM_OPTIONSMENUHELP :
842 hh_aklink.pszKeywords = "Options Menu" ;
843 break ;
844
845 case CM_TOOLSMENUHELP :
846 hh_aklink.pszKeywords = "Tools Menu" ;
847 break ;
848
849 case CM_WINDOWMENUHELP :
850 hh_aklink.pszKeywords = "Window Menu" ;
851 break ;
852
853 case CM_RENDERWINMENUHELP :
854 hh_aklink.pszKeywords = "Render Window Menu" ;
855 break ;
856
857 case CM_MESSAGEWINMENUHELP :
858 hh_aklink.pszKeywords = "Message Window Menu" ;
859 break ;
860
861 default :
862 hh_aklink.pszKeywords = NULL ;
863 break ;
864 }
865 if (hh_aklink.pszKeywords != NULL)
866 HtmlHelp (NULL, engineHelpPath, HH_KEYWORD_LOOKUP, (DWORD_PTR) &hh_aklink) ;
867 }
868
869 // example taken from MSDN documentation
GetDllVersion(LPCTSTR lpszDllName)870 DWORD GetDllVersion (LPCTSTR lpszDllName)
871 {
872 HINSTANCE hinstDll;
873 DWORD dwVersion = 0;
874
875 hinstDll = LoadLibrary(lpszDllName) ;
876
877 if (hinstDll)
878 {
879 DLLGETVERSIONPROC pDllGetVersion;
880
881 pDllGetVersion = (DLLGETVERSIONPROC) GetProcAddress (hinstDll, "DllGetVersion");
882
883 if (pDllGetVersion)
884 {
885 DLLVERSIONINFO dvi;
886 HRESULT hr;
887
888 ZeroMemory(&dvi, sizeof (dvi));
889 dvi.cbSize = sizeof (dvi);
890
891 hr = (*pDllGetVersion) (&dvi);
892
893 if (SUCCEEDED (hr))
894 dwVersion = MAKELONG (dvi.dwMajorVersion, dvi.dwMinorVersion);
895 }
896
897 FreeLibrary (hinstDll);
898 }
899 return dwVersion;
900 }
901
getvars(ExternalVarStruct * v)902 void getvars (ExternalVarStruct *v)
903 {
904 strcpy (v->command_line, command_line) ;
905 strcpy (v->source_file_name, source_file_name) ;
906 strcpy (v->lastRenderName, lastRenderName) ;
907 strcpy (v->lastRenderPath, lastRenderPath) ;
908 strcpy (v->lastQueuePath, lastQueuePath) ;
909 strcpy (v->lastSecondaryIniFilePath, lastSecondaryIniFilePath) ;
910 strcpy (v->DefaultRenderIniFileName, DefaultRenderIniFileName) ;
911 strcpy (v->SecondaryRenderIniFileName, SecondaryRenderIniFileName) ;
912 strcpy (v->SecondaryRenderIniFileSection, SecondaryRenderIniFileSection) ;
913 strcpy (v->ourPath, modulePath) ;
914 strcpy (v->engineHelpPath, engineHelpPath) ;
915 strcpy (v->rendererHelpPath, "") ;
916 strcpy (v->BinariesPath, BinariesPath) ;
917 strcpy (v->EngineIniFileName, EngineIniFileName) ;
918 strcpy (v->ToolIniFileName, ToolIniFileName) ;
919 memcpy (v->queued_files, queued_files, sizeof (v->queued_files)) ;
920 v->loadRerun = false ;
921 v->continueRerun = false ;
922 v->povray_return_code = povray_return_code ;
923 v->rendering = rendering ;
924 v->IsWin32 = true ;
925 v->IsW95UserInterface = IsW95UserInterface ;
926 v->running_demo = running_demo ;
927 v->debugging = debugging ;
928 v->isMaxiMinimized = false ;
929 v->newVersion = newVersion ;
930 v->use_threads = true ;
931 v->use_toolbar = use_toolbar ;
932 v->use_tooltips = use_tooltips ;
933 v->use_editors = use_editors ;
934 v->drop_to_editor = drop_to_editor ;
935 v->rendersleep = rendersleep ;
936 v->ExtensionsEnabled = ExtensionsEnabled ;
937 v->queued_file_count = queued_file_count > OLD_MAX_QUEUE ? OLD_MAX_QUEUE : queued_file_count ;
938 v->auto_render = auto_render ;
939 }
940
setvars(ExternalVarStruct * v)941 void setvars (ExternalVarStruct *v)
942 {
943 strncpy (command_line, v->command_line, sizeof (command_line) - 1) ;
944 SendMessage (toolbar_cmdline, WM_SETTEXT, 0, (LPARAM) command_line) ;
945 strncpy (source_file_name, v->source_file_name, sizeof (source_file_name) - 1) ;
946 strncpy (lastRenderName, v->lastRenderName, sizeof (lastRenderName) - 1) ;
947 strncpy (lastRenderPath, v->lastRenderPath, sizeof (lastRenderPath) - 1) ;
948 strncpy (lastQueuePath, v->lastQueuePath, sizeof (lastQueuePath) - 1) ;
949 strncpy (lastSecondaryIniFilePath, v->lastSecondaryIniFilePath, sizeof (lastSecondaryIniFilePath) - 1) ;
950 strncpy (DefaultRenderIniFileName, v->DefaultRenderIniFileName, sizeof (DefaultRenderIniFileName) - 1) ;
951 strncpy (SecondaryRenderIniFileName, v->SecondaryRenderIniFileName, sizeof (SecondaryRenderIniFileName) - 1) ;
952 strncpy (SecondaryRenderIniFileSection, v->SecondaryRenderIniFileSection, sizeof (SecondaryRenderIniFileSection) - 1) ;
953 }
954
HaveWin95OrLater(void)955 bool HaveWin95OrLater (void)
956 {
957 return (version_info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) ;
958 }
959
HaveWin98OrLater(void)960 bool HaveWin98OrLater (void)
961 {
962 if (version_info.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS)
963 return (false) ;
964 if (version_info.dwMajorVersion < 4)
965 return (false) ;
966 if (version_info.dwMajorVersion > 4)
967 return (true) ;
968 return (version_info.dwMinorVersion > 0) ;
969 }
970
HaveNT4OrLater(void)971 bool HaveNT4OrLater (void)
972 {
973 return (version_info.dwPlatformId == VER_PLATFORM_WIN32_NT && version_info.dwMajorVersion >= 4) ;
974 }
975
HaveWin2kOrLater(void)976 bool HaveWin2kOrLater (void)
977 {
978 return (version_info.dwPlatformId == VER_PLATFORM_WIN32_NT && version_info.dwMajorVersion >= 5) ;
979 }
980
HaveWinXPOrLater(void)981 bool HaveWinXPOrLater (void)
982 {
983 if (version_info.dwPlatformId != VER_PLATFORM_WIN32_NT || version_info.dwMajorVersion < 5)
984 return (false) ;
985 return (version_info.dwMajorVersion > 5 || (version_info.dwMajorVersion == 5 && version_info.dwMinorVersion > 0)) ;
986 }
987
HaveVistaOrLater(void)988 bool HaveVistaOrLater (void)
989 {
990 return version_info.dwPlatformId == VER_PLATFORM_WIN32_NT && version_info.dwMajorVersion > 5;
991 }
992
set_render_priority(unsigned priority)993 void set_render_priority (unsigned priority)
994 {
995 switch (priority)
996 {
997 case CM_RENDERPRIORITY_BACKGROUND :
998 SetPriorityClass (GetCurrentProcess(), PROCESS_MODE_BACKGROUND_BEGIN) ;
999 break ;
1000
1001 case CM_RENDERPRIORITY_LOW :
1002 if (IsVista)
1003 SetPriorityClass (GetCurrentProcess(), PROCESS_MODE_BACKGROUND_END);
1004 SetPriorityClass (GetCurrentProcess(), IDLE_PRIORITY_CLASS) ;
1005 break ;
1006
1007 case CM_RENDERPRIORITY_NORMAL :
1008 if (IsVista)
1009 SetPriorityClass (GetCurrentProcess(), PROCESS_MODE_BACKGROUND_END);
1010 SetPriorityClass (GetCurrentProcess(), BELOW_NORMAL_PRIORITY_CLASS) ;
1011 break ;
1012
1013 case CM_RENDERPRIORITY_HIGH :
1014 if (IsVista)
1015 SetPriorityClass (GetCurrentProcess(), PROCESS_MODE_BACKGROUND_END);
1016 SetPriorityClass (GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS) ;
1017 break ;
1018 }
1019 }
1020
1021 // we can't allow LoadBitmap to load our background bitmaps 'cause if we're running
1022 // a 256-colour mode, it will map the incoming resource to 16 colours ...
1023 // LoadImage () doesn't exist under Win32s, either. sigh.
NonBogusLoadBitmap(HINSTANCE hInst,LPSTR lpszBitmap)1024 HBITMAP NonBogusLoadBitmap (HINSTANCE hInst, LPSTR lpszBitmap)
1025 {
1026 void *p ;
1027 HRSRC hres ;
1028 HGLOBAL hg ;
1029 HBITMAP hBitmap ;
1030
1031 if ((hres = FindResource (hInst, lpszBitmap, RT_BITMAP)) == NULL)
1032 return (NULL) ;
1033 if ((hg = LoadResource (hInst, hres)) == NULL)
1034 return (NULL) ;
1035 if ((p = LockResource (hg)) == NULL)
1036 {
1037 FreeResource (hg) ;
1038 return (NULL) ;
1039 }
1040 hBitmap = lpDIBToBitmap (p, hPalApp) ;
1041 FreeResource (hg) ;
1042 return (hBitmap) ;
1043 }
1044
NonBogusLoadBitmapAndPalette(HINSTANCE hInst,LPSTR lpszBitmap)1045 HBITMAP NonBogusLoadBitmapAndPalette (HINSTANCE hInst, LPSTR lpszBitmap)
1046 {
1047 void *p ;
1048 HRSRC hres ;
1049 HGLOBAL hg ;
1050 HBITMAP hBitmap ;
1051
1052 if ((hres = FindResource (hInst, lpszBitmap, RT_BITMAP)) == NULL)
1053 return (NULL) ;
1054 if ((hg = LoadResource (hInst, hres)) == NULL)
1055 return (NULL) ;
1056 if ((p = LockResource (hg)) == NULL)
1057 {
1058 FreeResource (hg) ;
1059 return (NULL) ;
1060 }
1061 hBitmap = lpDIBToBitmapAndPalette (p) ;
1062 FreeResource (hg) ;
1063 return (hBitmap) ;
1064 }
1065
1066 // finds fist separator character in a path
findFirstPathSeparator(char * s)1067 char *findFirstPathSeparator (char *s)
1068 {
1069 size_t pos = strcspn(s, "\\/");
1070
1071 return pos >= strlen(s) ? NULL : s + pos;
1072 }
1073
1074 // finds last separator character in a path
findLastPathSeparator(char * s)1075 char *findLastPathSeparator (char *s)
1076 {
1077 char *s1 = strrchr (s, '\\');
1078 char *s2 = strrchr (s1 ? s1 : s, '/');
1079
1080 return s2 ? s2 : s1;
1081 }
1082
1083 // append separator character to a path, if not present already
1084 // does not append to empty strings.
1085 // does append to solitary drive letters; this isn't quite legit but as we don't
1086 // support the use of drive references without a path (i.e. references that rely
1087 // on the uniquely-DOS/Windows concept of a CWD for *each* mounted device), it
1088 // doesn't really matter.
appendPathSeparator(char * str)1089 void appendPathSeparator (char *str)
1090 {
1091 if (str[0] != '\0') // only append to non-empty strings
1092 if (!hasTrailingPathSeparator(str))
1093 strcat(str, "\\");
1094 }
1095
1096 // tests if path has trailing separator character
1097 // does not return true if path is a solitary drive letter (e.g. "C:").
1098 // the same consideration applies regarding relative drive references as
1099 // mentioned in appendPathSeparator.
hasTrailingPathSeparator(const char * str)1100 bool hasTrailingPathSeparator (const char *str)
1101 {
1102 return isPathSeparator(str[strlen (str) - 1]);
1103 }
1104
1105 // strips trailing separator character from path
1106 // will strip a trailing separator right after drive letter (e.g. "C:\").
1107 // calling functions must be careful not to let this trip them up if they
1108 // are passed any user-specified input.
trimTrailingPathSeparator(char * str)1109 void trimTrailingPathSeparator (char *str)
1110 {
1111 char *s = str + strlen (str) - 1 ;
1112 if (isPathSeparator(*s))
1113 *s = '\0' ;
1114 }
1115
1116 // strips leading and trailing double-quotes from a string.
1117 // does not check that both are present, just removes them
1118 // if they are there. returns new start of string.
trimDoubleQuotes(char * str)1119 char *trimDoubleQuotes (char *str)
1120 {
1121 if (str[0] == '"')
1122 str++;
1123 char *s = str + strlen (str) - 1 ;
1124 if (*s == '"')
1125 *s = '\0' ;
1126 return str;
1127 }
1128
1129 // strips trailing separator character from path
validatePath(char * s)1130 void validatePath (char *s)
1131 {
1132 if (s [1] == ':' && strlen (s) < 4)
1133 return ; // make sure we don't trim a trailing separator right after a drive letter (e.g. "C:\")
1134 trimTrailingPathSeparator (s);
1135 }
1136
joinPath(char * out,const char * path,const char * name)1137 int joinPath (char *out, const char *path, const char *name)
1138 {
1139 strcpy (out, path) ;
1140 appendPathSeparator (out);
1141 strcat (out, name) ;
1142 return ((int) strlen (out)) ;
1143 }
1144
reg_printf(bool useHKCU,char * keyName,char * valName,char * format,...)1145 bool reg_printf (bool useHKCU, char *keyName, char *valName, char *format, ...)
1146 {
1147 char str [2048] ;
1148 HKEY hKey ;
1149 va_list arg_ptr ;
1150
1151 if (strlen (format) > sizeof (str) - 256)
1152 return (false) ;
1153 if (RegCreateKeyEx (useHKCU ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE, keyName, 0, "", REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL) == ERROR_SUCCESS)
1154 {
1155 va_start (arg_ptr, format) ;
1156 vsprintf (str, format, arg_ptr) ;
1157 va_end (arg_ptr) ;
1158 RegSetValueEx (hKey, valName, 0, REG_SZ, (BYTE *) str, (int) strlen (str) + 1) ;
1159 RegCloseKey (hKey) ;
1160 return (true) ;
1161 }
1162 return (false) ;
1163 }
1164
1165 // conditional version of reg_printf
cond_reg_printf(char * keyName,char * valName,char * format,...)1166 bool cond_reg_printf (char *keyName, char *valName, char *format, ...)
1167 {
1168 char str [2048] ;
1169 DWORD len = sizeof (str) ;
1170 HKEY hKey ;
1171 va_list arg_ptr ;
1172
1173 if (strlen (format) > sizeof (str) - 256)
1174 return (false) ;
1175 if (RegOpenKeyEx (HKEY_CURRENT_USER, keyName, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
1176 {
1177 if (RegQueryValueEx (hKey, valName, 0, NULL, (BYTE *) str, &len) == ERROR_SUCCESS)
1178 {
1179 RegCloseKey (hKey) ;
1180 // it already exists - if it doesn't have zero length we don't update it
1181 if (str [0])
1182 return (true) ;
1183 }
1184 else
1185 RegCloseKey (hKey) ;
1186 }
1187 if (RegCreateKeyEx (HKEY_CURRENT_USER, keyName, 0, "", REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL) == ERROR_SUCCESS)
1188 {
1189 va_start (arg_ptr, format) ;
1190 vsprintf (str, format, arg_ptr) ;
1191 va_end (arg_ptr) ;
1192 RegSetValueEx (hKey, valName, 0, REG_SZ, (BYTE *) str, (int) strlen (str) + 1) ;
1193 RegCloseKey (hKey) ;
1194 return (true) ;
1195 }
1196 return (false) ;
1197 }
1198
reg_dword(char * keyName,char * valName,DWORD value)1199 static bool reg_dword (char *keyName, char *valName, DWORD value)
1200 {
1201 HKEY hKey ;
1202
1203 if (RegCreateKeyEx (HKEY_CURRENT_USER, keyName, 0, "", REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL) == ERROR_SUCCESS)
1204 {
1205 RegSetValueEx (hKey, valName, 0, REG_DWORD, (BYTE *) &value, 4) ;
1206 RegCloseKey (hKey) ;
1207 return (true) ;
1208 }
1209 return (false) ;
1210 }
1211
GetInstallTime(void)1212 char *GetInstallTime (void)
1213 {
1214 HKEY key ;
1215 DWORD len ;
1216 static char str [64] ;
1217
1218 len = sizeof (str) ;
1219 if (RegOpenKeyEx (HKEY_CURRENT_USER, "Software\\" REGKEY, 0, KEY_READ, &key) == ERROR_SUCCESS)
1220 {
1221 if (RegQueryValueEx (key, INSTALLTIMEKEY, 0, NULL, (BYTE *) str, &len) == ERROR_SUCCESS)
1222 {
1223 RegCloseKey (key) ;
1224 return (str) ;
1225 }
1226 RegCloseKey (key) ;
1227 }
1228 return (NULL) ;
1229 }
1230
checkRegKey(void)1231 bool checkRegKey (void)
1232 {
1233 char str [_MAX_PATH] ;
1234 HKEY key ;
1235 DWORD val;
1236 DWORD len = sizeof (str) ;
1237 FILETIME file_time ;
1238 SYSTEMTIME system_time ;
1239
1240 if (GetInstallTime () == NULL)
1241 {
1242 GetSystemTime (&system_time) ;
1243 if (SystemTimeToFileTime (&system_time, &file_time))
1244 reg_printf (true, "Software\\" REGKEY, INSTALLTIMEKEY, "%I64u", ((__int64) file_time.dwHighDateTime << 32) | file_time.dwLowDateTime) ;
1245 }
1246
1247 if (RegOpenKeyEx (HKEY_CURRENT_USER, "Software\\" REGKEY "\\" REGVERKEY "\\Windows", 0, KEY_READ, &key) == ERROR_SUCCESS)
1248 {
1249 if (RegQueryValueEx (key, "Home", 0, NULL, (BYTE *) str, &len) != 0)
1250 str[0] = '\0';
1251 if (str [0] == '\0')
1252 {
1253 RegCloseKey (key) ;
1254 return (false) ;
1255 }
1256 len = sizeof(val);
1257 if (RegQueryValueEx (key, "FreshInstall", 0, NULL, (BYTE *) &val, &len) == 0)
1258 {
1259 FreshInstall = val != 0;
1260 RegCloseKey (key) ;
1261 if (FreshInstall && RegOpenKeyEx (HKEY_CURRENT_USER, "Software\\" REGKEY "\\" REGVERKEY "\\Windows", 0, KEY_READ | KEY_SET_VALUE, &key) == ERROR_SUCCESS)
1262 {
1263 RegDeleteValue(key, "FreshInstall");
1264 RegCloseKey (key) ;
1265 }
1266 }
1267 else
1268 RegCloseKey (key) ;
1269 }
1270 else
1271 return (false) ;
1272
1273 if (RegOpenKeyEx (HKEY_CURRENT_USER, "Software\\" REGKEY "\\CurrentVersion\\Windows", 0, KEY_READ | KEY_WRITE, &key) == ERROR_SUCCESS)
1274 {
1275 len = sizeof (str) ;
1276 if (RegQueryValueEx (key, VERSIONVAL, 0, NULL, (BYTE *) str, &len) != 0 || strcmp (str, POV_RAY_VERSION) != 0)
1277 RegSetValueEx (key, VERSIONVAL, 0, REG_SZ, (BYTE *) POV_RAY_VERSION, (int) strlen (POV_RAY_VERSION) + 1) ;
1278 RegCloseKey (key) ;
1279 }
1280
1281 return true;
1282 }
1283
getHome(void)1284 bool getHome (void)
1285 {
1286 HKEY key ;
1287 DWORD len ;
1288
1289 if (debugging)
1290 debug_output ("querying registry\n") ;
1291 DocumentsPath [0] = BinariesPath [0] = '\0' ;
1292 if (RegOpenKeyEx (HKEY_CURRENT_USER, "Software\\" REGKEY "\\" REGVERKEY "\\Windows", 0, KEY_READ, &key) == ERROR_SUCCESS)
1293 {
1294 len = sizeof (LastInferredHome) ;
1295 RegQueryValueEx (key, "LastInferredHome", 0, NULL, (BYTE *) LastInferredHome, &len) ;
1296
1297 len = sizeof (BinariesPath) ;
1298 RegQueryValueEx (key, "Home", 0, NULL, (BYTE *) BinariesPath, &len) ;
1299 if (debugging && BinariesPath[0] != '\0')
1300 debug_output("Win32 getHome() succeeded (HKCU::Home), BinariesPath is '%s'\n", BinariesPath) ;
1301
1302 len = sizeof (DocumentsPath) ;
1303 RegQueryValueEx (key, "DocPath", 0, NULL, (BYTE *) DocumentsPath, &len) ;
1304 if (debugging && DocumentsPath[0] != '\0')
1305 debug_output("Win32 getHome() succeeded (HKCU::DocPath), DocumentsPath is '%s'\n", DocumentsPath) ;
1306
1307 RegCloseKey (key) ;
1308 return (BinariesPath[0] != '\0') ;
1309 }
1310 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, "Software\\" REGKEY "\\" REGVERKEY "\\Windows", 0, KEY_READ, &key) == ERROR_SUCCESS)
1311 {
1312 len = sizeof (BinariesPath) ;
1313 RegQueryValueEx (key, "Home", 0, NULL, (BYTE *) BinariesPath, &len) ;
1314 RegCloseKey (key) ;
1315 if (debugging && BinariesPath[0] != '\0')
1316 debug_output("Win32 getHome() succeeded (HKLM::Home), BinariesPath is '%s'\n", BinariesPath) ;
1317 return (BinariesPath[0] != '\0') ;
1318 }
1319 return (false) ;
1320 }
1321
inferHome(void)1322 bool inferHome (void)
1323 {
1324 char exePath [_MAX_PATH] ;
1325 char *s ;
1326
1327 if (GetModuleFileName (NULL, exePath, _MAX_PATH) == 0)
1328 return (false) ;
1329
1330 // find path component
1331 if ((s = findLastPathSeparator (exePath)) == NULL)
1332 return (false) ;
1333 *s = '\0' ;
1334
1335 // now step up one directory
1336 if ((s = findLastPathSeparator (exePath)) == NULL)
1337 return (false) ;
1338 *++s = '\0' ;
1339
1340 // now look for some standard directories
1341 strcpy (s, "help") ;
1342 if (!dirExists (exePath))
1343 {
1344 strcpy (s, "sounds") ;
1345 if (!dirExists (exePath))
1346 {
1347 strcpy (s, "tiles") ;
1348 if (!dirExists (exePath))
1349 return (false) ;
1350 }
1351 }
1352
1353 *s = '\0' ;
1354 strcpy (BinariesPath, exePath) ;
1355 homeInferred = true ;
1356 return (true) ;
1357 }
1358
get36Home(void)1359 string get36Home(void)
1360 {
1361 char str[_MAX_PATH];
1362 HKEY key ;
1363 DWORD len = sizeof(str);
1364
1365 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, "Software\\" REGKEY "\\v3.6\\Windows", 0, KEY_READ, &key) == ERROR_SUCCESS)
1366 {
1367 if (RegQueryValueEx (key, "Home", 0, NULL, (BYTE *) str, &len) == 0)
1368 {
1369 RegCloseKey (key) ;
1370 appendPathSeparator(str);
1371 return string(str);
1372 }
1373 RegCloseKey (key) ;
1374 }
1375 if (RegOpenKeyEx (HKEY_CURRENT_USER, "Software\\" REGKEY "\\v3.6\\Windows", 0, KEY_READ, &key) == ERROR_SUCCESS)
1376 {
1377 if (RegQueryValueEx (key, "Home", 0, NULL, (BYTE *) str, &len) == 0)
1378 {
1379 RegCloseKey (key) ;
1380 appendPathSeparator(str);
1381 return string(str);
1382 }
1383 RegCloseKey (key) ;
1384 }
1385 return string();
1386 }
1387
copy36EditSettings(void)1388 bool copy36EditSettings(void)
1389 {
1390 HKEY hKeySrc ;
1391 HKEY hKeyDst ;
1392 DWORD result ;
1393 HINSTANCE hLib ;
1394 shCopyType *shCopyKey ;
1395
1396 if ((hLib = LoadLibrary ("shlwapi.dll")) == NULL)
1397 return (false) ;
1398 shCopyKey = (shCopyType *) GetProcAddress (hLib, "SHCopyKeyA") ;
1399 if (shCopyKey == NULL)
1400 {
1401 FreeLibrary (hLib) ;
1402 return (false) ;
1403 }
1404
1405 if (RegOpenKeyEx (HKEY_CURRENT_USER, "Software\\" REGKEY "\\v3.6", 0, KEY_READ, &hKeySrc) != ERROR_SUCCESS)
1406 {
1407 FreeLibrary (hLib) ;
1408 return (false) ;
1409 }
1410
1411 if (RegCreateKeyEx (HKEY_CURRENT_USER, "Software\\" REGKEY "\\" REGVERKEY "\\POV-Edit", 0, "", REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKeyDst, NULL) != ERROR_SUCCESS)
1412 {
1413 RegCloseKey (hKeySrc) ;
1414 FreeLibrary (hLib) ;
1415 return (false) ;
1416 }
1417
1418 result = shCopyKey (hKeySrc, "POV-Edit", hKeyDst, NULL) ;
1419 RegCloseKey (hKeySrc) ;
1420 RegCloseKey (hKeyDst) ;
1421 FreeLibrary (hLib) ;
1422
1423 return (result == ERROR_SUCCESS) ;
1424 }
1425
checkEditKey36(void)1426 bool checkEditKey36 (void)
1427 {
1428 HKEY key ;
1429
1430 if (RegOpenKeyEx (HKEY_CURRENT_USER, "Software\\" REGKEY "\\v3.6\\POV-Edit", 0, KEY_READ, &key) == ERROR_SUCCESS)
1431 {
1432 RegCloseKey (key) ;
1433 return (true) ;
1434 }
1435 return (false) ;
1436 }
1437
checkEditKey37(void)1438 bool checkEditKey37 (void)
1439 {
1440 HKEY key ;
1441
1442 if (RegOpenKeyEx (HKEY_CURRENT_USER, "Software\\" REGKEY "\\" REGVERKEY "\\POV-Edit", 0, KEY_READ, &key) == ERROR_SUCCESS)
1443 {
1444 RegCloseKey (key) ;
1445 return (true) ;
1446 }
1447 return (false) ;
1448 }
1449
1450 // called if either our registry entries don't seem to be set up, or if they do exist and
1451 // the FreshInstall option is set in the registry.
CloneOptions(void)1452 bool CloneOptions (void)
1453 {
1454 if (debugging)
1455 debug_output("attempting to create registry entries\n") ;
1456
1457 // don't do this if we're being called as a result of the FreshInstall registry setting
1458 if (!FreshInstall)
1459 {
1460 if (!reg_printf (true, "Software\\" REGKEY "\\" REGVERKEY "\\Windows", "Home", "%s", BinariesPath))
1461 return (false) ;
1462 if (!homeInferred)
1463 reg_printf (true, "Software\\" REGKEY "\\CurrentVersion\\Windows", "Home", "%s", BinariesPath) ;
1464 }
1465
1466 reg_printf (true, "Software\\" REGKEY "\\CurrentVersion\\Windows", VERSIONVAL, "%s", POV_RAY_VERSION) ;
1467
1468 cond_reg_printf ("Software\\" REGKEY "\\" REGVERKEY "\\POV-Edit\\Open", "Open0", "%sChanges.txt,1,1,0,0,8,2", DocumentsPath) ;
1469 cond_reg_printf ("Software\\" REGKEY "\\" REGVERKEY "\\POV-Edit\\Recent", "Recent0", "%sChanges.txt,1,1,0,0,8,2", DocumentsPath) ;
1470 cond_reg_printf ("Software\\" REGKEY "\\" REGVERKEY "\\POV-Edit\\Open", "Open1", "%sRevision.txt,1,1,0,0,8,2", DocumentsPath) ;
1471 cond_reg_printf ("Software\\" REGKEY "\\" REGVERKEY "\\POV-Edit\\Recent", "Recent1", "%sRevision.txt,1,1,0,0,8,2", DocumentsPath) ;
1472 cond_reg_printf ("Software\\" REGKEY "\\" REGVERKEY "\\POV-Edit\\Open", "Open2", "%sscenes\\advanced\\biscuit.pov,1,1,0,6,8,2", DocumentsPath) ;
1473 cond_reg_printf ("Software\\" REGKEY "\\" REGVERKEY "\\POV-Edit\\Recent", "Recent2", "%sscenes\\advanced\\biscuit.pov,1,1,0,6,8,2", DocumentsPath) ;
1474 cond_reg_printf ("Software\\" REGKEY "\\" REGVERKEY "\\POV-Edit\\Open", "Open3", "%sscenes\\advanced\\woodbox.pov,1,1,0,6,8,2", DocumentsPath) ;
1475 cond_reg_printf ("Software\\" REGKEY "\\" REGVERKEY "\\POV-Edit\\Recent", "Recent3", "%sscenes\\advanced\\woodbox.pov,1,1,0,6,8,2", DocumentsPath) ;
1476
1477 return (true) ;
1478 }
1479
parse_commandline(char * s)1480 int parse_commandline (char *s)
1481 {
1482 char *prevWord = NULL ;
1483 char inQuote = '\0' ;
1484 static char str [_MAX_PATH * 3] ;
1485 static char filename [_MAX_PATH] ;
1486
1487 argc = 0 ;
1488 GetModuleFileName (hInstance, filename, sizeof (filename) - 1) ;
1489 argv [argc++] = filename ;
1490 s = strncpy (str, s, sizeof (str) - 1) ;
1491 while (*s)
1492 {
1493 switch (*s)
1494 {
1495 case '"' :
1496 case '\'' :
1497 if (inQuote)
1498 {
1499 if (*s == inQuote)
1500 inQuote = 0 ;
1501 }
1502 else
1503 {
1504 inQuote = *s ;
1505 if (prevWord == NULL)
1506 prevWord = s ;
1507 }
1508 break ;
1509
1510 case ' ' :
1511 case '\t' :
1512 if (!inQuote)
1513 {
1514 if (prevWord != NULL)
1515 {
1516 *s = '\0' ;
1517 argv [argc++] = prevWord ;
1518 prevWord = NULL ;
1519 }
1520 }
1521 break ;
1522
1523 default :
1524 if (prevWord == NULL)
1525 prevWord = s ;
1526 break ;
1527 }
1528 if (argc >= MAX_ARGV - 1)
1529 break ;
1530 s++ ;
1531 }
1532 if (prevWord != NULL && argc < MAX_ARGV - 1)
1533 argv [argc++] = prevWord ;
1534 argv [argc] = NULL ;
1535 return (argc) ;
1536 }
1537
InstallSettings(char * binpath,char * docpath,bool quiet)1538 int InstallSettings (char *binpath, char *docpath, bool quiet)
1539 {
1540 char base [_MAX_PATH] ;
1541 char str [_MAX_PATH] ;
1542 char *s ;
1543
1544 // we attempt to infer the install dir if it's not supplied
1545 if (binpath == NULL)
1546 {
1547 if (_getcwd (base, sizeof (base) - 1) == NULL)
1548 {
1549 if (!quiet)
1550 MessageBox (NULL, "Could not get current directory - cannot infer home path. Please supply it on the command-line",
1551 "POV-Ray for Windows - running INSTALL option", MB_OK | MB_ICONSTOP) ;
1552 return 5 ;
1553 }
1554 if (strlen (base) < 3 || (strlen (base) == 3 && base [1] == ':' && isPathSeparator(base [2])))
1555 {
1556 if (!quiet)
1557 {
1558 sprintf (str, "Current dir '%s' is root - cannot infer home path. Please supply it on the command-line.", base) ;
1559 MessageBox (NULL, str, "POV-Ray for Windows - running INSTALL option", MB_OK | MB_ICONSTOP) ;
1560 }
1561 return 10 ;
1562 }
1563 // the strlen test covers the case where base is "\\" (i.e. a network path) or a bare drive (e.g. "c:").
1564 if (!StripPathComponent (base, 1) || strlen(base) < 3)
1565 {
1566 if (!quiet)
1567 MessageBox (NULL, "Cannot infer home path. Please supply it on the command-line.",
1568 "POV-Ray for Windows - running INSTALL option", MB_OK | MB_ICONSTOP) ;
1569 return 15 ;
1570 }
1571 }
1572 else
1573 {
1574 strcpy (str, binpath) ;
1575 s = trimDoubleQuotes(str);
1576 validatePath (s) ;
1577 if (GetFullPathName (s, sizeof (base), base, NULL) == 0)
1578 {
1579 sprintf (str, "GetFullPathName() for '%s' failed [0x%08x]", s, GetLastError ()) ;
1580 MessageBox (NULL, str, "POV-Ray for Windows - running INSTALL option", MB_OK | MB_ICONSTOP) ;
1581 }
1582 }
1583 if (!dirExists (base))
1584 {
1585 if (!quiet)
1586 {
1587 sprintf (str, "Could not stat directory '%s'", base) ;
1588 MessageBox (NULL, str, "POV-Ray for Windows - running INSTALL option", MB_OK | MB_ICONSTOP) ;
1589 }
1590 return 20 ;
1591 }
1592
1593 if (docpath != NULL)
1594 {
1595 if (!dirExists(docpath))
1596 {
1597 // if the path doesn't exist and quiet is selected, we continue, assuming that
1598 // by the time povray is ready to be used, it will either exist or be able to be
1599 // created. note that we do auto-create the path if possible (i.e. the parent
1600 // directory exists and is writable by the user who launches POV-Ray).
1601 if (!quiet)
1602 if (MessageBox (NULL, "Could not verify supplied user files path: use it anyway?\n(Selecting NO will exit.)", "POV-Ray for Windows - running INSTALL option", MB_YESNO | MB_ICONEXCLAMATION) == IDNO)
1603 return 30;
1604 }
1605 reg_printf (true, "Software\\" REGKEY "\\" REGVERKEY "\\Windows", "DocPath", "%s\\", docpath);
1606 }
1607
1608 if (!reg_printf (true, "Software\\" REGKEY "\\" REGVERKEY "\\Windows", "Home", "%s\\", base))
1609 {
1610 if (!quiet)
1611 MessageBox (NULL, "Failed to write to HKCU in registry", "POV-Ray for Windows - running INSTALL option", MB_OK | MB_ICONSTOP) ;
1612 return 35 ;
1613 }
1614
1615 // it's ok for this to fail as they may not have administrative rights
1616 reg_printf (false, "Software\\" REGKEY "\\" REGVERKEY "\\Windows", "Home", "%s\\", base) ;
1617
1618 if (!quiet)
1619 {
1620 sprintf (str, "[Home path is %s]\n\nSuccess!", base) ;
1621 MessageBox (NULL, str, "POV-Ray for Windows - running INSTALL option", MB_OK | MB_ICONINFORMATION) ;
1622 }
1623 return (0) ;
1624 }
1625
GetExceptionDescription(DWORD code)1626 char *GetExceptionDescription (DWORD code)
1627 {
1628 switch (code)
1629 {
1630 case EXCEPTION_ACCESS_VIOLATION :
1631 return ("a memory access violation") ;
1632
1633 case EXCEPTION_DATATYPE_MISALIGNMENT :
1634 return ("a datatype misalignment") ;
1635
1636 case EXCEPTION_FLT_DENORMAL_OPERAND :
1637 return ("a denormal floating point operand") ;
1638
1639 case EXCEPTION_FLT_DIVIDE_BY_ZERO :
1640 return ("a floating point divide by zero") ;
1641
1642 case EXCEPTION_FLT_INEXACT_RESULT :
1643 return ("an inexact floating-point result") ;
1644
1645 case EXCEPTION_FLT_INVALID_OPERATION :
1646 return ("an invalid floating-point operation") ;
1647
1648 case EXCEPTION_FLT_OVERFLOW :
1649 return ("a floating-point overflow") ;
1650
1651 case EXCEPTION_FLT_STACK_CHECK :
1652 return ("a floating-point stack over/underflow") ;
1653
1654 case EXCEPTION_FLT_UNDERFLOW :
1655 return ("a floating-point underflow") ;
1656
1657 case EXCEPTION_INT_DIVIDE_BY_ZERO :
1658 return ("an integer divide by zero") ;
1659
1660 case EXCEPTION_INT_OVERFLOW :
1661 return ("an integer overflow") ;
1662
1663 case EXCEPTION_PRIV_INSTRUCTION :
1664 return ("the execution of a privileged instruction") ;
1665
1666 case EXCEPTION_IN_PAGE_ERROR :
1667 return ("a page error") ;
1668
1669 case EXCEPTION_ILLEGAL_INSTRUCTION :
1670 return ("the execution of an illegal instruction") ;
1671
1672 case EXCEPTION_NONCONTINUABLE_EXCEPTION :
1673 return ("a continuation after a noncontinuable exception") ;
1674
1675 case EXCEPTION_STACK_OVERFLOW :
1676 return ("a stack overflow") ;
1677
1678 case EXCEPTION_INVALID_DISPOSITION :
1679 return ("an invalid disposition") ;
1680
1681 case EXCEPTION_GUARD_PAGE :
1682 return ("a guard page exception") ;
1683
1684 case EXCEPTION_INVALID_HANDLE :
1685 return ("an invalid handle exception") ;
1686
1687 default :
1688 return NULL ;
1689 }
1690 }
1691
1692 #if POV_RAY_IS_OFFICIAL == 1
1693 // this pulls in the code for update checks and crash dump submission.
1694 // it is only used in official releases made by the POV-Ray developers,
1695 // so the source is not included in the public distribution.
1696 #include "official.h"
1697 #else
ExceptionHandler(struct _EXCEPTION_POINTERS * ExceptionInfo)1698 LONG WINAPI ExceptionHandler(struct _EXCEPTION_POINTERS* ExceptionInfo)
1699 {
1700 char *s;
1701 long timestamp = _time32(NULL);
1702 PCONTEXT c ;
1703 static char str[2048] ;
1704 static boost::mutex mtx;
1705 boost::mutex::scoped_lock l(mtx);
1706
1707 c = ExceptionInfo->ContextRecord ;
1708 const char *desc = GetExceptionDescription(ExceptionInfo->ExceptionRecord->ExceptionCode);
1709 if (desc == NULL)
1710 desc = "an" ;
1711 sprintf (str,
1712 "Unfortunately, it appears that %s at address 0x%p has caused this unofficial POV-Ray build to crash. "
1713 "This dialog will allow you to choose whether or not a dump file (useful for diagnostics) is written.\n\n"
1714 "NOTE: If you were running a render, you should be able to recover the part that had already been generated. "
1715 "See the 'Continue' (+c) option in the documentation for more information about this.\n\n"
1716 "Would you like to write a dump file?",
1717 desc,
1718 #ifdef _WIN64
1719 c->Rip);
1720 #else
1721 c->Eip);
1722 #endif
1723 DWORD result = MessageBox (NULL, str, "POV-Ray for Windows", MB_ICONSTOP | MB_TOPMOST | MB_TASKMODAL | MB_YESNO | MB_DEFBUTTON1 | MB_SETFOREGROUND) ;
1724 if (result == IDYES)
1725 {
1726 // write a full dump first, then a minidump. it's no big deal if the full dump write fails.
1727 WriteDump(ExceptionInfo, true, timestamp);
1728 if ((s = WriteDump(ExceptionInfo, false, timestamp)) != NULL)
1729 {
1730 MessageBox (main_window, "The dump was successfully saved.", "POV-Ray for Windows", MB_OK) ;
1731 sprintf(str, "/select,%s", s);
1732 ShellExecute (NULL, NULL, "explorer.exe", str, NULL, SW_SHOWNORMAL) ;
1733 ExitProcess (1) ;
1734 }
1735 }
1736 else
1737 MessageBox (main_window, "POV-Ray will now exit.", "POV-Ray for Windows", MB_OK) ;
1738 ExitProcess (1) ;
1739 return (EXCEPTION_CONTINUE_SEARCH) ; // make compiler happy
1740 }
1741 #endif // POV_RAY_IS_OFFICIAL
1742
execute_tool(char * s)1743 int execute_tool (char *s)
1744 {
1745 int error ;
1746 STARTUPINFO startupInfo ;
1747 PROCESS_INFORMATION procInfo ;
1748
1749 if (strlen (s) == 0)
1750 {
1751 PovMessageBox ("No command to run!", "Tool Error") ;
1752 return (0) ;
1753 }
1754
1755 if (*s == '$')
1756 {
1757 switch (toupper (s[1]))
1758 {
1759 case 'S' :
1760 s += 2 ;
1761 while (*s == ' ')
1762 s++ ;
1763 if (strlen (s) == 0)
1764 {
1765 PovMessageBox ("No file to open!", "Tool Error") ;
1766 return (0) ;
1767 }
1768 if ((error = PtrToInt (ShellExecute (main_window, "open", s, NULL, NULL, SW_SHOWNORMAL))) <= 32)
1769 PovMessageBox ("ShellExecute failed", "Tool Error") ;
1770 return (error) ;
1771
1772 case 'E' :
1773 s += 2 ;
1774 while (*s == ' ')
1775 s++ ;
1776 if (strlen (s) == 0)
1777 {
1778 PovMessageBox ("No file to open!", "Tool Error") ;
1779 return (0) ;
1780 }
1781 return EditOpenFile(s) ? 0 : 1;
1782 }
1783 }
1784
1785 startupInfo.cb = sizeof (STARTUPINFO) ;
1786 startupInfo.lpReserved = 0 ;
1787 startupInfo.lpDesktop = NULL ;
1788 startupInfo.lpTitle = NULL ;
1789 startupInfo.dwX = 0 ;
1790 startupInfo.dwY = 0 ;
1791 startupInfo.dwXSize = 0 ;
1792 startupInfo.dwYSize = 0 ;
1793 startupInfo.dwXCountChars = 0 ;
1794 startupInfo.dwYCountChars = 0 ;
1795 startupInfo.dwFillAttribute = 0 ;
1796 startupInfo.dwFlags = STARTF_USESHOWWINDOW ;
1797 startupInfo.wShowWindow = SW_SHOW ;
1798 startupInfo.cbReserved2 = 0 ;
1799 startupInfo.lpReserved2 = 0 ;
1800
1801 if (CreateProcess (NULL, s, NULL, NULL, false, 0, NULL, NULL, &startupInfo, &procInfo) == false)
1802 {
1803 error = GetLastError () ;
1804 PovMessageBox ("Could not run program", "Tool Error") ;
1805 return (error) ;
1806 }
1807
1808 // clean up
1809 CloseHandle (procInfo.hProcess) ;
1810 CloseHandle (procInfo.hThread) ;
1811
1812 return (0) ;
1813 }
1814
RenderInsertMenu(void)1815 void RenderInsertMenu (void)
1816 {
1817 int val ;
1818 char str [_MAX_PATH] ;
1819 char *s1 ;
1820 char *s2 ;
1821 FILE *f ;
1822
1823 stop_rendering = false ;
1824 sprintf (str, "%sInsert Menu\\Images.ini", DocumentsPath) ;
1825 if ((f = fopen (str, "rt")) == NULL)
1826 {
1827 MessageBox (main_window, "Cannot open 'Images.ini' in Insert Menu directory", "Insert Menu Images", MB_OK | MB_ICONEXCLAMATION) ;
1828 return ;
1829 }
1830 InsertMenuSection = 0 ;
1831 InsertMenuSections.clear();
1832 while (fgets (str, sizeof (str), f) != NULL)
1833 {
1834 s1 = clean (str) ;
1835 if (*s1 == '[')
1836 {
1837 if ((s2 = strchr (s1, ']')) != NULL)
1838 {
1839 *s2 = '\0' ;
1840 val = atoi (++s1) ;
1841 if (val == 0)
1842 continue ;
1843 InsertMenuSections.push_back(val);
1844 if (InsertMenuSections.size() == MAX_INSERT_MENU_SECTIONS)
1845 break ;
1846 }
1847 }
1848 }
1849 fclose (f) ;
1850 if (InsertMenuSections.empty())
1851 {
1852 MessageBox (main_window, "No insert menu sections found in 'Images.ini'", "Insert Menu Images", MB_OK | MB_ICONSTOP) ;
1853 return ;
1854 }
1855 sprintf (str, "There are %u insert menu images to render. Press OK to start rendering these now.\n\n"
1856 "Once the render has started you can press the 'Stop Rendering' button to cancel the render job.", (unsigned int) InsertMenuSections.size()) ;
1857 if (MessageBox (main_window, str, "Insert Menu Images", MB_OKCANCEL | MB_ICONINFORMATION) == IDCANCEL)
1858 return ;
1859 PVEnableMenuItem (CM_RENDERSHOW, MF_GRAYED) ;
1860 update_menu_for_render (true) ;
1861 rendering_insert_menu = was_insert_render = no_status_output = true ;
1862 EditShowMessages (true) ;
1863 CalculateClientWindows (true) ;
1864 ShowWindow (message_window, SW_SHOW) ;
1865 sprintf (str, "%sInsert Menu", DocumentsPath) ;
1866 SetCurrentDirectory (str) ;
1867 StartInsertRender = true ;
1868 }
1869
GetUCS2String(POVMSObjectPtr object,POVMSType key,char * result,int * maxlen)1870 int GetUCS2String(POVMSObjectPtr object, POVMSType key, char *result, int *maxlen)
1871 {
1872 UCS2 *str = new UCS2 [*maxlen] ;
1873 int err = POVMSUtil_GetUCS2String (object, key, str, maxlen) ;
1874 if (err == kNoErr)
1875 {
1876 string abc = UCS2toASCIIString (str) ;
1877 strcpy (result, abc.c_str ()) ;
1878 }
1879 delete str ;
1880 return err ;
1881 }
1882
ShowIsPaused(void)1883 void ShowIsPaused(void)
1884 {
1885 if (GetSession().BackendFailed() == false && rendersleep == false)
1886 {
1887 SleepTimeStart = clock () ;
1888 status_printf (StatusPPS, PPS_String (GetSession().GetPixelsRendered(), ClockTimeTotal / CLOCKS_PER_SEC)) ;
1889 say_status_message (StatusPPS, "PAUSED") ;
1890 rendersleep = true ;
1891 SendMessage (toolbar_window, TB_CHECKBUTTON, (WPARAM) CM_RENDERSLEEP, MAKELONG (1, 0)) ;
1892 }
1893 }
1894
getCommandLine(void)1895 char *getCommandLine (void)
1896 {
1897 HKEY key ;
1898 static char str [2048] ;
1899 DWORD len = sizeof (str) ;
1900
1901 str [0] = '\0' ;
1902 if (RegOpenKeyEx (HKEY_CURRENT_USER, "Software\\" REGKEY "\\" REGVERKEY "\\Windows", 0, KEY_READ, &key) == ERROR_SUCCESS)
1903 {
1904 RegQueryValueEx (key, "Command Line", 0, NULL, (BYTE *) str, &len) ;
1905 RegCloseKey (key) ;
1906 }
1907 return (str) ;
1908 }
1909
setRunOnce(void)1910 void setRunOnce (void)
1911 {
1912 #ifndef NOSETRUNONCE
1913 char str [_MAX_PATH] ;
1914 HKEY key ;
1915 DWORD result ;
1916
1917 if (RegCreateKeyEx (HKEY_CURRENT_USER,
1918 "Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce",
1919 0,
1920 "",
1921 REG_OPTION_NON_VOLATILE,
1922 KEY_WRITE,
1923 NULL,
1924 &key,
1925 &result) == ERROR_SUCCESS)
1926 {
1927 GetModuleFileName (hInstance, str, sizeof (str)) ;
1928 RegSetValueEx (key, "POV-Ray for Windows", 0, REG_SZ, (BYTE *) str, (int) strlen (str) + 1) ;
1929 RegCloseKey (key) ;
1930 }
1931 #endif
1932 }
1933
display_cleanup(bool unconditional)1934 void display_cleanup (bool unconditional)
1935 {
1936 if (unconditional)
1937 {
1938 gDisplay.reset();
1939 return;
1940 }
1941 Display *d = gDisplay.get();
1942 if (d == NULL)
1943 return;
1944 WinDisplay *wd = dynamic_cast<WinDisplay *>(d);
1945 if (wd == NULL)
1946 return;
1947 if (wd->GetWidth() != render_width || wd->GetHeight() != render_height)
1948 {
1949 gDisplay.reset();
1950 return;
1951 }
1952 wd->Clear();
1953 }
1954
cancel_render(void)1955 void cancel_render (void)
1956 {
1957 stop_rendering = true ;
1958 if (GetSession().BackendFailed())
1959 {
1960 render_stopped() ;
1961 return;
1962 }
1963 if (GetSession().CancelRender() == vfeNotRunning)
1964 {
1965 // we possibly have an anamolous situation
1966 MessageBox (NULL, "Warning: had to force state to stopped", "Cancel Render", MB_OK | MB_ICONEXCLAMATION) ;
1967 render_stopped() ;
1968 }
1969 }
1970
1971 // TODO: we have a problem here - if the parse completes very quickly, it's
1972 // possible for the VFE code to process the change to rendering mode before
1973 // we exit start_rendering() [note that the VFE worker thread runs at a higher
1974 // priority than the main UI thread]. as a result, on occasion, the VFE code
1975 // will call the display's Show() method at the same time as we are executing
1976 // display_cleanup(). display_cleanup() can cause the value of the pointer in
1977 // gDisplay to change, and potentially destroy the old one ...
start_rendering(bool ignore_source_file)1978 bool start_rendering (bool ignore_source_file)
1979 {
1980 int threadCount = ThreadCount ;
1981 char str [sizeof (command_line)] ;
1982 char path [_MAX_PATH] ;
1983 char file [_MAX_PATH] ;
1984 vfeSession& Session (GetSession());
1985
1986 if (Session.BackendFailed())
1987 {
1988 MessageBox (main_window, "The render backend has shut down due to an error: please re-start POV-Ray", "Error", MB_OK | MB_ICONSTOP) ;
1989 return false;
1990 }
1991
1992 Session.Clear();
1993 Session.ClearOptions();
1994 if (!keep_messages)
1995 clear_messages(false);
1996
1997 if (running_benchmark)
1998 threadCount = benchmark_mode || benchmark_multithread ? ThreadCount : 1 ;
1999
2000 ErrorOccurred = ErrorNotified = false ;
2001 ErrorMessage.clear() ;
2002 ErrorFilename.clear() ;
2003 status_buffer [0] = '\0' ;
2004 povray_return_code = 0 ;
2005 rendersleep = false ;
2006 SleepTimeTotal = 0 ;
2007 render_anim_count = 0 ;
2008 rendering_animation = false ;
2009 stop_rendering = false ;
2010 was_insert_render = false ;
2011 first_frame = true ;
2012 render_width = render_height = 0 ;
2013 KernelTimeStart = GetCPUTime (true, false) ;
2014 UserTimeStart = GetCPUTime (false, true) ;
2015 CPUTimeTotal = KernelTimeTotal = UserTimeTotal = 0 ;
2016 ClockTimeStart = clock () ;
2017 SecondCountStart = time (NULL) ;
2018 SleepTimeTotal = ClockTimeTotal = 0 ;
2019 status_printf (StatusPPS, "") ;
2020 say_status_message (StatusRendertime, "") ;
2021 output_to_file = false ;
2022 InputFileName.clear();
2023 LastRenderPercentage = 0;
2024
2025 SendMessage (StatusPanelItems [IDC_STATUS_PROGRESS].hwnd, PBM_SETPOS, 0, 0) ;
2026
2027 say_status_message (StatusMessage, "") ;
2028
2029 PVEnableMenuItem (CM_RENDERSHOW, MF_GRAYED) ;
2030 update_menu_for_render (true) ;
2031 SendMessage (toolbar_combobox, CB_GETLBTEXT, SendMessage (toolbar_combobox, CB_GETCURSEL, 0, 0), (LPARAM) SecondaryRenderIniFileSection) ;
2032
2033 if (!StartInsertRender)
2034 {
2035 if (!temp_render_region)
2036 if (RegionStr [0] != '\0' && strstr (command_line, RegionStr + 1) == NULL)
2037 RegionStr [0] = '\0' ;
2038 }
2039
2040 if (save_settings)
2041 {
2042 if (restore_command_line)
2043 {
2044 strcpy (str, command_line) ;
2045 strcpy (command_line, old_command_line) ;
2046 }
2047 write_INI_settings (true) ;
2048 if (restore_command_line)
2049 strcpy (command_line, str) ;
2050 EditSaveState () ;
2051 }
2052
2053 try
2054 {
2055 // set up render options
2056 vfeRenderOptions opts ;
2057
2058 opts.SetThreadCount (threadCount);
2059 opts.AddINI (DefaultRenderIniFileName) ;
2060
2061 if (AutoAppendPaths || homeInferred)
2062 {
2063 sprintf (str, "%sinclude", DocumentsPath) ;
2064 opts.AddLibraryPath (str);
2065 opts.AddLibraryPath (FontPath);
2066 }
2067
2068 if (!StartInsertRender)
2069 {
2070 if (running_demo == 0)
2071 {
2072 if (SecondaryRenderIniFileName [0] != '\0')
2073 {
2074 if (!hasTrailingPathSeparator(SecondaryRenderIniFileName))
2075 {
2076 splitpath (SecondaryRenderIniFileName, NULL, str) ;
2077 if (str [0] != '\0')
2078 {
2079 if (SecondaryRenderIniFileSection [0] == '\0')
2080 wrapped_printf ("Preset INI file is '%s'.", SecondaryRenderIniFileName) ;
2081 else
2082 wrapped_printf ("Preset INI file is '%s', section is '%s'.", SecondaryRenderIniFileName, SecondaryRenderIniFileSection) ;
2083 sprintf (str, "%s%s", SecondaryRenderIniFileName, SecondaryRenderIniFileSection) ;
2084 opts.AddINI (str);
2085 }
2086 }
2087 }
2088
2089 if (!ignore_source_file && strlen (source_file_name) != 0)
2090 {
2091 wrapped_printf ("Preset source file is '%s'.", source_file_name) ;
2092 splitpath (source_file_name, dir, NULL) ;
2093 SetCurrentDirectory (dir) ;
2094 sprintf (str, "%s\\povray.ini", dir) ;
2095 if (fileExists (str))
2096 {
2097 wrapped_printf ("File '%s' exists - merging it.", str) ;
2098 opts.AddINI (str);
2099 }
2100 switch (get_file_type (source_file_name))
2101 {
2102 case filePOV :
2103 case fileINC :
2104 opts.SetSourceFile (source_file_name);
2105 break ;
2106
2107 case fileINI :
2108 opts.AddINI (source_file_name);
2109 break ;
2110
2111 default :
2112 message_printf ("POV-Ray for Windows doesn't recognize this file type ; assuming POV source.\n") ;
2113 opts.SetSourceFile (source_file_name);
2114 break ;
2115 }
2116 }
2117 }
2118
2119 if (running_benchmark)
2120 {
2121 opts.AddINI (demo_ini_name) ;
2122 opts.SetSourceFile (demo_file_name) ;
2123 if (strlen (demo_file_name) != 0)
2124 {
2125 splitpath (demo_file_name, dir, NULL) ;
2126 SetCurrentDirectory (dir) ;
2127 }
2128 }
2129 else
2130 {
2131 if (RegionStr [0] != 0)
2132 {
2133 if (strstr (command_line, RegionStr) == NULL && strstr (command_line, RegionStr + 1) == NULL)
2134 {
2135 if (!running_demo)
2136 message_printf ("Selected render region is '%s'.\n", RegionStr + 1) ;
2137 opts.AddCommand (RegionStr);
2138 }
2139 }
2140
2141 if (strlen (command_line))
2142 {
2143 if (!running_demo)
2144 wrapped_printf ("Rendering using command line '%s'.", command_line) ;
2145 opts.AddCommand (command_line);
2146 }
2147 }
2148 }
2149 else
2150 {
2151 // we are rendering the insert menu
2152 if (InsertMenuSection >= InsertMenuSections.size())
2153 throw POV_EXCEPTION_STRING("Insert menu render error - we should be stopped already!");
2154 int section = InsertMenuSections [InsertMenuSection] ;
2155 sprintf (str, "Images.ini[%d]", section) ;
2156 opts.AddINI (str);
2157 }
2158
2159 int result = Session.SetOptions (opts) ;
2160 if (result == vfeNoInputFile)
2161 throw POV_EXCEPTION_STRING("No source file specified, either directly or via an INI file.");
2162 else if (result != vfeNoError)
2163 throw POV_EXCEPTION_STRING (Session.GetErrorString());
2164
2165 // TODO FIXME - magic values
2166 if (opts.GetOptions().TryGetInt(kPOVAttrib_RenderBlockSize, 32) < 4)
2167 throw POV_EXCEPTION (kParseErr, "Minimum permitted render block size is 4 (+BS4 or Render_Block_Size=4)") ;
2168
2169 InputFileName = UCS2toASCIIString (Session.GetInputFilename());
2170 output_to_file = opts.GetOptions().TryGetBool(kPOVAttrib_OutputToFile, true) ;
2171 render_width = Session.GetRenderWidth();
2172 render_height = Session.GetRenderHeight();
2173 PutHKCU("LastRender", "SceneFile", "") ;
2174 PutHKCU("LastRender", "OutputFile", "") ;
2175 PutHKCU("LastRender", "IniOutputFile", "") ;
2176 PutHKCU("LastRender", "IniOutputFile", "") ;
2177
2178 UseAlpha = Session.GetBoolOption("Output_Alpha", false);
2179 if (Session.GetBoolOption("Display", true) == false)
2180 display_cleanup(true);
2181
2182 if (StartInsertRender)
2183 status_printf (StatusMessage, "Rendering Insert Menu entry %d of %d", InsertMenuSection + 1, (unsigned int) InsertMenuSections.size()) ;
2184 else
2185 status_printf (StatusMessage, "Parsing %s", InputFileName.c_str()) ;
2186
2187 if (!running_demo && !demo_mode && !benchmark_mode)
2188 {
2189 GetCurrentDirectory (sizeof (dir), dir) ;
2190 PutHKCU("LastRender", "CurrentDirectory", dir) ;
2191 splitpath ((char *) InputFileName.c_str (), path, file) ;
2192 PutHKCU("LastRender", "SourceFile", get_full_name (file)) ;
2193 splitfn (str, NULL, file, NULL) ;
2194 PutHKCU("LastRender", "SceneFile", file) ;
2195 }
2196
2197 result = Session.StartRender();
2198 if (result < 0)
2199 throw POV_EXCEPTION_CODE (result);
2200 else if (result > 0)
2201 throw POV_EXCEPTION_STRING (Session.GetErrorString());
2202 }
2203 catch (std::exception& e)
2204 {
2205 int errorCode = 0 ;
2206 if (dynamic_cast<pov_base::Exception *> (&e) != NULL)
2207 {
2208 errorCode = dynamic_cast<pov_base::Exception *> (&e)->code() ;
2209 povray_return_code = errorCode ;
2210 }
2211 if (povray_return_code == 0)
2212 povray_return_code = -1 ;
2213 ErrorOccurred = true ;
2214 PVEnableMenuItem (CM_RENDERSHOW, MF_ENABLED) ;
2215 update_menu_for_render (false) ;
2216 if (restore_command_line)
2217 {
2218 strcpy (command_line, old_command_line) ;
2219 SendMessage (toolbar_cmdline, WM_SETTEXT, 0, (UINT_PTR) command_line) ;
2220 restore_command_line = false ;
2221 }
2222
2223 // make sure any outstanding messages are processed
2224 ProcessSession();
2225
2226 EditShowMessages (true) ;
2227
2228 if (ErrorNotified == false)
2229 {
2230 sprintf (str, "Failed to start render: %s", e.what()) ;
2231 say_status_message (StatusMessage, str) ;
2232 message_printf ("%s\n", str) ;
2233 }
2234 if (errorCode != kCannotOpenFileErr && errorCode != kParseErr && errorCode != kOutOfMemoryErr)
2235 {
2236 sprintf (str, "Failed to set render options (%s).\nSee message pane for more details.", e.what()) ;
2237 MessageBox (main_window, str, "Error", MB_OK | MB_ICONSTOP) ;
2238 }
2239
2240 if (ErrorFilename.empty() == false)
2241 EditShowParseError (ErrorFilename.c_str(), ErrorMessage.c_str(), ErrorLine, ErrorCol) ;
2242 if (parse_error_sound_enabled)
2243 {
2244 PlaySound (parse_error_sound, NULL, SND_NOWAIT | SND_ASYNC | SND_NODEFAULT) ;
2245 if (!running_demo && !demo_mode && !benchmark_mode)
2246 FeatureNotify ("ParserErrorSound",
2247 "POV-Ray - Parse Error Sound",
2248 "You can change the sound played upon parse errors "
2249 "from the Render Menu.\n\n"
2250 "Click Help for more information.",
2251 "sounds", false) ;
2252 }
2253 buffer_message (mDivider, "\n") ;
2254 EditShowMessages (true) ;
2255
2256 return (false) ;
2257 }
2258
2259 if (!StartInsertRender)
2260 {
2261 if (MenuBarDraw)
2262 {
2263 DrawMenuBar (main_window) ;
2264 MenuBarDraw = false ;
2265 }
2266 bool show = EditShowMessages (true) ;
2267 CalculateClientWindows (true) ;
2268 if (show)
2269 ShowWindow (message_window, SW_SHOW) ;
2270 PutHKCU ("Info", "Rendering", 1) ;
2271 display_cleanup (false) ;
2272 }
2273
2274 currentX = seconds_for_last_line = -1 ;
2275 message_printf ("Rendering with %d thread%s.\n", threadCount, threadCount > 1 ? "s" : "") ;
2276
2277 if (GetRenderWindow())
2278 GetRenderWindow()->SetRenderState (true);
2279
2280 ExternalEvent (EventStartRendering, 0) ;
2281
2282 set_render_priority (render_priority) ;
2283
2284 // FIXME - ought to wait for the render to start here
2285 rendering = true ;
2286 // StartProfile () ;
2287
2288 return (true) ;
2289 }
2290
render_stopped(void)2291 void render_stopped (void)
2292 {
2293 char *s ;
2294 char str [4096] ;
2295 vfeWinSession& Session (GetSession());
2296
2297 run_renderer = false ;
2298 rendering = false ;
2299 status_buffer[0] = '\0' ;
2300 delay_next_status = 0 ;
2301 SetStatusPanelItemText (IDC_STATUS_DATA_FRAME, "N/A") ;
2302 SendMessage (StatusPanelItems [IDC_STATUS_PROGRESS].hwnd, PBM_SETPOS, 0, 0) ;
2303 bool success = Session.Succeeded();
2304
2305 if (message_output_x > 0)
2306 buffer_message (mIDE, "\n") ;
2307
2308 s = EditGetFilename(true) ;
2309 if (s != NULL && *s != '\0')
2310 {
2311 sprintf (str, "POV-Ray - %s", s) ;
2312 SetCaption (str) ;
2313 }
2314 else
2315 SetCaption ("POV-Ray for Windows") ;
2316
2317 if ((!success || ErrorOccurred) && povray_return_code == 0)
2318 povray_return_code = -1 ;
2319 PrintRenderTimes (true, !ErrorOccurred && !stop_rendering) ;
2320 ExternalEvent (EventStopRendering, povray_return_code) ;
2321
2322 // EndProfile () ;
2323
2324 if (restore_command_line && !rendering_insert_menu)
2325 {
2326 strcpy (command_line, old_command_line) ;
2327 SendMessage (toolbar_cmdline, WM_SETTEXT, 0, (LPARAM) command_line) ;
2328 restore_command_line = false ;
2329 }
2330
2331 if (rendering_insert_menu)
2332 {
2333 if (InsertMenuSection < InsertMenuSections.size() - 1 && !(stop_rendering || quit))
2334 {
2335 wrapped_printf ("Completed rendering Insert Menu section %d. result = %d", InsertMenuSections [InsertMenuSection++], povray_return_code) ;
2336 StartInsertRender = true ;
2337 return ;
2338 }
2339 StartInsertRender = rendering_insert_menu = no_status_output = false ;
2340 was_insert_render = true ;
2341 }
2342 else if (running_benchmark || running_demo)
2343 {
2344 if (running_benchmark == false)
2345 {
2346 strcpy (command_line, old_command_line) ;
2347 restore_command_line = false ;
2348 }
2349 _unlink (demo_file_name) ;
2350 _unlink (demo_ini_name) ;
2351 running_benchmark = running_demo = false ;
2352 if (benchmark_mode) // only applies to benchmarks started from the command-line
2353 PostQuitMessage (0) ;
2354 if (demo_mode)
2355 {
2356 PovMessageBox ("Demonstration completed. POV-Ray will now exit.", "Finished test run") ;
2357 PostQuitMessage (0) ;
2358 }
2359 }
2360
2361 PutHKCU("Info", "Rendering", 0U) ;
2362 set_render_priority (CM_RENDERPRIORITY_NORMAL) ;
2363
2364 if (quit != 0 || exit_after_render)
2365 {
2366 DestroyWindow (main_window) ;
2367 return ;
2368 }
2369
2370 WinDisplay *rw = GetRenderWindow();
2371 if (rw != NULL)
2372 {
2373 rw->SetCaption ("POV-Ray Render Window");
2374 rw->SetRenderState (false);
2375 if (render_auto_close)
2376 rw->Hide();
2377 }
2378 if (main_window_hidden)
2379 TaskBarModifyIcon (main_window, 0, "POV-Ray (Restore: DblClk ; Menu: Mouse2)") ;
2380 InvalidateRect (statuspanel, NULL, false) ;
2381
2382 if (success == true && ErrorOccurred == false)
2383 {
2384 if (render_complete_sound_enabled)
2385 {
2386 PlaySound (render_complete_sound, NULL, SND_ASYNC | SND_NODEFAULT) ;
2387 if (!running_demo && !demo_mode && !benchmark_mode)
2388 FeatureNotify ("RenderCompleteSound",
2389 "POV-Ray - Render Complete Sound",
2390 "You can change the sound played upon completion of rendering "
2391 "from the Render Menu.\n\nIt is also possible to tell POV-Ray "
2392 "for Windows to do other things when a render stops (such as "
2393 "display a message or exit.)",
2394 "sounds", false) ;
2395 }
2396 say_status_message (StatusMessage, "") ;
2397 EditShowMessages (false) ;
2398 CalculateClientWindows (false) ;
2399 switch (on_completion)
2400 {
2401 case CM_COMPLETION_EXIT :
2402 DestroyWindow (main_window) ;
2403 break ;
2404
2405 case CM_COMPLETION_MESSAGE :
2406 PovMessageBox ("Render completed", "Message from POV-Ray for Windows") ;
2407 break ;
2408 }
2409 if (!running_demo && !demo_mode && !benchmark_mode && !rendering_insert_menu && !running_benchmark && !was_insert_render)
2410 {
2411 string ofn = UCS2toASCIIString (Session.GetOutputFilename());
2412 if (output_to_file && ofn.size () != 0)
2413 {
2414 sprintf (str, "Output -> '%s'", ofn.c_str ()) ;
2415 say_status_message (StatusMessage, str) ;
2416 //buffer_stream_message (mIDE, str) ;
2417 sprintf (str, "Your output file has been written to the following location:\n\n"
2418 " %s\n\n"
2419 "Press F1 to learn more about how to control where files are written.",
2420 ofn.c_str ()) ;
2421 FeatureNotify ("OutputFileLocation", "POV-Ray - Output File Notification", str, "Output_File_Name", false) ;
2422 PutHKCU("LastRender", "OutputFile", ofn.c_str ()) ;
2423 }
2424 else
2425 {
2426 if (!running_benchmark)
2427 {
2428 FeatureNotify ("OutputFileOff",
2429 "POV-Ray - No Output File",
2430 "A render has completed but file output was turned off. No file "
2431 "was written.\n\nPress F1 for help on output file control.",
2432 "Output_To_File",
2433 false) ;
2434 }
2435 }
2436 }
2437 }
2438 else
2439 {
2440 if (ErrorNotified == false && ErrorMessage.empty() == false)
2441 say_status_message (StatusMessage, ErrorMessage.c_str()) ;
2442 else if (stop_rendering)
2443 say_status_message (StatusMessage, "Render cancelled by user") ;
2444 else
2445 say_status_message (StatusMessage, "Render failed") ;
2446 if (ErrorFilename.empty() == false)
2447 EditShowParseError (ErrorFilename.c_str(), ErrorMessage.c_str(), ErrorLine, ErrorCol) ;
2448 if (stop_rendering)
2449 {
2450 if (render_error_sound_enabled)
2451 {
2452 PlaySound (render_error_sound, NULL, SND_ASYNC | SND_NODEFAULT) ;
2453 if (!running_demo && !demo_mode && !benchmark_mode)
2454 FeatureNotify ("RenderErrorSound",
2455 "POV-Ray - Render Stopped Sound",
2456 "You can change the sound played upon render errors/cancellation "
2457 "from the Render Menu.",
2458 "sounds", false) ;
2459 }
2460 }
2461 else
2462 {
2463 if (parse_error_sound_enabled)
2464 {
2465 PlaySound (parse_error_sound, NULL, SND_NOWAIT | SND_ASYNC | SND_NODEFAULT) ;
2466 if (!running_demo && !demo_mode && !benchmark_mode)
2467 FeatureNotify ("ParserErrorSound",
2468 "POV-Ray - Parse Error Sound",
2469 "You can change the sound played upon parse errors "
2470 "from the Render Menu.\n\n"
2471 "Click Help for more information.",
2472 "sounds", false) ;
2473 }
2474 }
2475 }
2476
2477 // update the mapping of included files to source files
2478 const std::set<string>& rf = Session.GetReadFiles();
2479 for (std::set<string>::const_iterator it = rf.begin(); it != rf.end(); it++)
2480 {
2481 if (_stricmp(it->c_str(), InputFileName.c_str()) == 0)
2482 continue;
2483 if (is_non_primary_file(it->c_str()))
2484 {
2485 FileType ft = get_file_type(it->c_str());
2486 if (ft < fileFirstImageType || ft > fileLastImageType)
2487 {
2488 std::pair<std::map<string, string>::iterator, bool> result = IncludeToSourceMap.insert(std::pair<string, string> (*it, InputFileName));
2489 if (result.second == false)
2490 result.first->second = InputFileName;
2491 }
2492 }
2493 }
2494 }
2495
ofn_hook_fn(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)2496 UINT WINAPI ofn_hook_fn (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2497 {
2498 switch (message)
2499 {
2500 case WM_INITDIALOG :
2501 SetupExplorerDialog (hwnd) ;
2502 break ;
2503 }
2504 return (false) ;
2505 }
2506
init_ofn(OPENFILENAME * ofn,HWND hWnd,char * title,char * name,int maxlen,char * lastPath,char * defaultExt)2507 void init_ofn (OPENFILENAME *ofn, HWND hWnd, char *title, char *name, int maxlen, char *lastPath, char *defaultExt)
2508 {
2509 ofn->lStructSize = sizeof (OPENFILENAME) ;
2510 ofn->hwndOwner = hWnd ;
2511 ofn->hInstance = hInstance ;
2512 ofn->lpstrCustomFilter = NULL ;
2513 ofn->nMaxCustFilter = 0 ;
2514 ofn->nFilterIndex = 1 ;
2515 ofn->lpstrTitle = title ;
2516 ofn->lpstrFile = name ;
2517 ofn->nMaxFile = maxlen ;
2518 ofn->lpstrFileTitle = NULL ;
2519 ofn->nMaxFileTitle = 0 ;
2520 ofn->lpstrInitialDir = lastPath ;
2521 ofn->Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR ;
2522 if (IsW95UserInterface)
2523 ofn->Flags |= OFN_EXPLORER ;
2524 ofn->nFileOffset = 0 ;
2525 ofn->nFileExtension = 0 ;
2526 ofn->lpstrDefExt = defaultExt ;
2527 ofn->lCustData = 0L ;
2528 ofn->lpfnHook = NULL ;
2529 ofn->lpTemplateName = NULL ;
2530 }
2531
file_open(HWND hWnd)2532 char *file_open (HWND hWnd)
2533 {
2534 int result ;
2535 OPENFILENAME ofnTemp ;
2536 static char name [_MAX_PATH] ;
2537
2538 strcpy (name, lastRenderName) ;
2539 validatePath (lastRenderPath) ;
2540 init_ofn (&ofnTemp, hWnd, "Render File", name, sizeof (name), lastRenderPath, "pov") ;
2541 ofnTemp.lpstrFilter = "POV source and INI (*.pov;*.ini)\0*.pov;*.ini\0POV files (*.pov)\0*.pov\0INI files (*.ini)\0*.ini\0Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0" ;
2542 if ((result = GetOpenFileName (&ofnTemp)) != 0)
2543 {
2544 strcpy (lastRenderPath, name) ;
2545 // this removes the name AND the trailing '\' [which is what we want]
2546 lastRenderPath [ofnTemp.nFileOffset - 1] = '\0' ;
2547 validatePath (lastRenderPath) ;
2548 strcpy (lastRenderName, name + ofnTemp.nFileOffset) ;
2549 }
2550 return (result ? name : NULL) ;
2551 }
2552
get_background_file(HWND hWnd)2553 char *get_background_file (HWND hWnd)
2554 {
2555 int result ;
2556 OPENFILENAME ofnTemp ;
2557 static char name [_MAX_PATH] ;
2558
2559 strcpy (name, lastBitmapName) ;
2560 validatePath (lastBitmapPath) ;
2561 init_ofn (&ofnTemp, hWnd, "Tile Bitmap File", name, sizeof (name), lastBitmapPath, "bmp") ;
2562 ofnTemp.lpstrFilter = "BMP files (*.bmp)\0*.bmp\0" ;
2563 if ((result = GetOpenFileName (&ofnTemp)) != 0)
2564 {
2565 strcpy (lastBitmapPath, name) ;
2566 lastBitmapPath [ofnTemp.nFileOffset - 1] = '\0' ;
2567 strcpy (lastBitmapName, name + ofnTemp.nFileOffset) ;
2568 }
2569 return (result ? name : NULL) ;
2570 }
2571
get_font(void)2572 void get_font (void)
2573 {
2574 HDC hdc ;
2575 HFONT hfont ;
2576 HFONT hfontOld ;
2577 LOGFONT lf ;
2578 CHOOSEFONT cf ;
2579 TEXTMETRIC tm ;
2580
2581 hdc = GetDC (message_window) ;
2582 memset(&cf, 0, sizeof (CHOOSEFONT)) ;
2583 cf.lStructSize = sizeof (CHOOSEFONT) ;
2584 cf.hwndOwner = main_window ;
2585 cf.lpLogFont = &lf ;
2586 cf.Flags = CF_SCREENFONTS | CF_FIXEDPITCHONLY | CF_FORCEFONTEXIST | CF_INITTOLOGFONTSTRUCT ;
2587 cf.nFontType = SCREEN_FONTTYPE ;
2588 get_logfont (hdc, &lf) ;
2589 if (ChooseFont (&cf))
2590 {
2591 if ((hfont = CreateFontIndirect (&lf)) == NULL)
2592 {
2593 PovMessageBox ("Failed to create message font", "Cannot change to selected font") ;
2594 ReleaseDC (message_window, hdc) ;
2595 return ;
2596 }
2597 hfontOld = (HFONT)SelectObject (hdc, hfont) ;
2598 GetTextMetrics (hdc, &tm) ;
2599 message_xchar = tm.tmAveCharWidth ;
2600 message_ychar = tm.tmHeight + tm.tmExternalLeading ;
2601 SelectObject (hdc, hfontOld) ;
2602 DeleteObject (message_font) ;
2603 message_font = hfont ;
2604 PovInvalidateRect (message_window, NULL, true) ;
2605 message_font_size = -MulDiv (lf.lfHeight, 72, GetDeviceCaps (hdc, LOGPIXELSY)) ;
2606 message_font_weight = lf.lfWeight ;
2607 strncpy (message_font_name, lf.lfFaceName, sizeof (message_font_name) - 1) ;
2608 }
2609 ReleaseDC (message_window, hdc) ;
2610 }
2611
DragFunction(HDROP handle)2612 void DragFunction (HDROP handle)
2613 {
2614 int cFiles ;
2615 int i ;
2616 char szFile [_MAX_PATH] ;
2617 HDIB hDIB ;
2618 bool calc = 0 ;
2619 BITMAP bm ;
2620
2621 cFiles = DragQueryFile (handle, -1, NULL, 0) ;
2622 if (rendering)
2623 message_printf ("\n") ;
2624 for (i = 0 ; i < cFiles ; i++)
2625 {
2626 DragQueryFile (handle, i, szFile, sizeof (szFile)) ;
2627 switch (get_file_type (szFile))
2628 {
2629 case filePOV :
2630 case fileINI :
2631 case fileINC :
2632 if (!use_editors || !drop_to_editor)
2633 break ;
2634 if ((EditGetFlags () & EDIT_CAN_OPEN) == 0)
2635 {
2636 say_status_message (StatusMessage, "Cannot open dropped file - max editor count reached") ;
2637 message_printf ("Cannot open dropped file - max editor count reached\n") ;
2638 }
2639 else
2640 EditOpenFile (szFile) ;
2641 continue ;
2642
2643 case fileBMP :
2644 if (screen_depth < 8)
2645 {
2646 PovMessageBox ("Tiled bitmaps not supported in this color depth", "File ignored") ;
2647 continue ;
2648 }
2649 if ((hDIB = LoadDIB (szFile)) != NULL)
2650 {
2651 strcpy (background_file, szFile) ;
2652 DeleteObject (hBmpBackground) ;
2653 hBmpBackground = DIBToBitmap (hDIB, hPalApp) ;
2654 DeleteObject (hDIB) ;
2655 GetObject (hBmpBackground, sizeof (BITMAP), (LPSTR) &bm) ;
2656 background_width = bm.bmWidth ;
2657 background_height = bm.bmHeight ;
2658 tile_background = true ;
2659 PovInvalidateRect (message_window, NULL, true) ;
2660 }
2661 else
2662 PovMessageBox ("Failed to load bitmap file", "Error") ;
2663 continue ;
2664
2665 default :
2666 if (!ExternalDragFunction (szFile, dfRealDrop))
2667 {
2668 if (!use_editors || !drop_to_editor)
2669 {
2670 say_status_message (StatusMessage, "Dropped file ignored (must be .POV, .INC, or .INI if destination is renderer)") ;
2671 wrapped_printf ("Dropped file '%s' ignored (must be .POV, .INC, or .INI if destination is renderer).", szFile) ;
2672 }
2673 else
2674 {
2675 if ((EditGetFlags () & EDIT_CAN_OPEN) == 0)
2676 {
2677 say_status_message (StatusMessage, "Cannot open dropped file - max editor count reached") ;
2678 message_printf ("Cannot open dropped file - max editor count reached\n") ;
2679 }
2680 else
2681 EditOpenFile (szFile) ;
2682 }
2683 }
2684 continue ;
2685 }
2686 if (queued_file_count < MAX_QUEUE)
2687 {
2688 strcpy (queued_files [queued_file_count++], szFile) ;
2689 wrapped_printf ("File '%s' dropped as queue entry %d.", szFile, queued_file_count) ;
2690 }
2691 else
2692 wrapped_printf ("render queue full ; file '%s' ignored.", szFile) ;
2693 }
2694 if (rendering)
2695 message_printf ("\n") ;
2696 DragFinish (handle) ;
2697 update_queue_status (true) ;
2698 if (calc)
2699 CalculateClientWindows (true) ;
2700 FeatureNotify ("DropFiles",
2701 "POV-Ray - Drag and Drop",
2702 "POV-Ray can do one of several things when you drop files onto it, "
2703 "depending on the state of the 'Drop to Editor' option and the type "
2704 "of file dropped. For example if the file is a .POV or .INI you can "
2705 "chose whether POV-Ray opens it or renders it.\n\nPress F1 for more "
2706 "information.",
2707 "drag and drop",
2708 true) ;
2709 }
2710
WIN_Debug_Log(unsigned int from,const char * msg)2711 void WIN_Debug_Log (unsigned int from, const char *msg)
2712 {
2713 if (debugging)
2714 OutputDebugString (msg) ;
2715 }
2716
2717 #if POV_RAY_IS_OFFICIAL != 1
WIN_PrintOtherCredits(void)2718 void WIN_PrintOtherCredits (void)
2719 {
2720 char *s = DISTRIBUTION_MESSAGE_2 ;
2721
2722 while (*s == ' ' || *s == '\t')
2723 s++ ;
2724 message_printf ("This is an UNSUPPORTED UNOFFICIAL COMPILE by %s.\n", s) ;
2725 }
2726 #endif
2727
PovMessageBox(const char * message,char * title)2728 void PovMessageBox (const char *message, char *title)
2729 {
2730 MessageBox (main_window, message, title, MB_ICONEXCLAMATION) ;
2731 }
2732
detect_graphics_config(void)2733 void detect_graphics_config (void)
2734 {
2735 HDC hdc ;
2736
2737 hdc = GetDC (NULL) ;
2738 screen_depth = GetDeviceCaps (hdc, BITSPIXEL) ;
2739 render_bitmap_depth = (GetDeviceCaps (hdc, BITSPIXEL) > 8 && renderwin_8bits == 0) ? 24 : 8 ;
2740 screen_width = GetDeviceCaps (hdc, HORZRES) ;
2741 screen_height = GetDeviceCaps (hdc, VERTRES) ;
2742 if (GetSystemMetrics (SM_CMONITORS) > 1)
2743 {
2744 screen_origin_x = GetSystemMetrics (SM_XVIRTUALSCREEN) ;
2745 screen_origin_y = GetSystemMetrics (SM_YVIRTUALSCREEN) ;
2746 virtual_screen_width = GetSystemMetrics (SM_CXVIRTUALSCREEN) ;
2747 virtual_screen_height = GetSystemMetrics (SM_CYVIRTUALSCREEN) ;
2748 }
2749 else
2750 {
2751 screen_origin_x = screen_origin_y = 0 ;
2752 virtual_screen_width = screen_width ;
2753 virtual_screen_height = screen_height ;
2754 }
2755 ReleaseDC (NULL, hdc) ;
2756 }
2757
2758 // Clear the system palette when we start to ensure an identity palette mapping
clear_system_palette(void)2759 void clear_system_palette (void)
2760 {
2761 int Counter ;
2762 HDC ScreenDC ;
2763 LogPal Palette = { 0x300, 256 } ;
2764 HPALETTE ScreenPalette ;
2765
2766 // Reset everything in the system palette to black
2767 for (Counter = 0 ; Counter < 256 ; Counter++)
2768 {
2769 Palette.pe [Counter].peRed = 0 ;
2770 Palette.pe [Counter].peGreen = 0 ;
2771 Palette.pe [Counter].peBlue = 0 ;
2772 Palette.pe [Counter].peFlags = PC_NOCOLLAPSE ;
2773 }
2774
2775 // Create, select, realize, deselect, and delete the palette
2776 ScreenDC = GetDC (NULL) ;
2777 ScreenPalette = CreatePalette ((LOGPALETTE *) &Palette) ;
2778 if (ScreenPalette)
2779 {
2780 ScreenPalette = SelectPalette (ScreenDC, ScreenPalette, false) ;
2781 RealizePalette (ScreenDC) ;
2782 ScreenPalette = SelectPalette (ScreenDC, ScreenPalette, false) ;
2783 DeleteObject (ScreenPalette) ;
2784 }
2785 ReleaseDC (NULL, ScreenDC) ;
2786 }
2787
create_about_font(void)2788 void create_about_font (void)
2789 {
2790 LOGFONT lf ;
2791
2792 HDC hdc = GetDC (NULL) ;
2793 memset (&lf, 0, sizeof (LOGFONT)) ;
2794 lf.lfHeight = -12 ;
2795 lf.lfWeight = FW_REGULAR ;
2796 lf.lfPitchAndFamily = VARIABLE_PITCH ;
2797 lf.lfCharSet = DEFAULT_CHARSET ;
2798 lf.lfQuality = PROOF_QUALITY ;
2799 strcpy (lf.lfFaceName, "Trebuchet MS") ;
2800 if ((about_font = CreateFontIndirect (&lf)) == NULL)
2801 {
2802 strcpy (lf.lfFaceName, "Arial") ;
2803 about_font = CreateFontIndirect (&lf) ;
2804 }
2805 ReleaseDC (NULL, hdc) ;
2806 }
2807
CalculateClientWindows(bool redraw)2808 void CalculateClientWindows (bool redraw)
2809 {
2810 RECT rect ;
2811
2812 GetClientRect (main_window, &rect) ;
2813 rect.bottom -= toolheight + statusheight ;
2814 if (!use_editors)
2815 MoveWindow (message_window, 0, toolheight, rect.right, rect.bottom, redraw) ;
2816 else
2817 SetEditorPosition (0, toolheight, rect.right, rect.bottom) ;
2818 }
2819
2820 // handle a WM_CHAR message destined for the toolbar commandline edit control.
2821 // return true if the message is to be discarded.
handle_toolbar_cmdline(UINT wParam,UINT lParam)2822 bool handle_toolbar_cmdline (UINT wParam, UINT lParam)
2823 {
2824 if (wParam == VK_RETURN)
2825 {
2826 SendMessage (main_window, WM_COMMAND, CM_FILERENDER, 0) ;
2827 return (true) ;
2828 }
2829 if (wParam == VK_ESCAPE)
2830 {
2831 EditSetFocus () ;
2832 return (true) ;
2833 }
2834 if (wParam == 0x01) // ctrl-a
2835 {
2836 SendMessage(toolbar_cmdline, EM_SETSEL, 0, -1);
2837 return (true) ;
2838 }
2839 return (false) ;
2840 }
2841
SetupStatusPanel(HWND hDlg)2842 void SetupStatusPanel (HWND hDlg)
2843 {
2844 int max = 0 ;
2845 int ypos = 0;
2846 char str [256] ;
2847 RECT rect ;
2848 StatusPanelItem item ;
2849
2850 GetWindowRect (hDlg, &rect) ;
2851 int x = rect.left ;
2852 int y = rect.top ;
2853 int width = rect.right - rect.left + 1 ;
2854 int height = rect.bottom - rect.top + 1 ;
2855 for (int id = IDC_STATUS_LABEL_FIRST ; id <= IDC_STATUS_ID_LAST ; id++)
2856 {
2857 item.id = id ;
2858 item.hwnd = GetDlgItem (hDlg, id) ;
2859 if (item.hwnd == NULL)
2860 continue ;
2861 if (id <= IDC_STATUS_DATA_LAST)
2862 {
2863 GetWindowText (item.hwnd, str, sizeof (str)) ;
2864 HDC hdc = GetDC (item.hwnd) ;
2865 HFONT hFont = (HFONT) SendMessage (item.hwnd, WM_GETFONT, 0, 0) ;
2866 HFONT oldFont = (HFONT) SelectObject (hdc, hFont) ;
2867 GetTextExtentPoint32 (hdc, str, (int) strlen (str), &item.size) ;
2868 SelectObject (hdc, oldFont) ;
2869 ReleaseDC (GetDlgItem (hDlg, id), hdc) ;
2870 if (id <= IDC_STATUS_LABEL_LAST)
2871 if (item.size.cx > max)
2872 max = item.size.cx ;
2873 }
2874 else
2875 {
2876 GetClientRect (item.hwnd, &rect) ;
2877 item.size.cx = rect.right ;
2878 item.size.cy = rect.bottom ;
2879 }
2880 StatusPanelItems [id] = item ;
2881 }
2882 for (int id = IDC_STATUS_LABEL_FIRST; id <= IDC_STATUS_LABEL_LAST ; id++)
2883 {
2884 item = StatusPanelItems [id] ;
2885 if (item.hwnd == NULL)
2886 continue ;
2887 MoveWindow (item.hwnd, 2, ypos, max + 2, item.size.cy, false) ;
2888 item = StatusPanelItems [id + IDC_STATUS_DATA_FIRST] ;
2889 MoveWindow (item.hwnd, max + 7, ypos, width - max - 8, item.size.cy, false) ;
2890 if (id >= IDC_STATUS_DATA_FIRST)
2891 SetWindowText (item.hwnd, "") ;
2892 ypos += item.size.cy ;
2893 }
2894 item = StatusPanelItems [IDC_STATUS_PROGRESS] ;
2895
2896 if (height - ypos > 6)
2897 {
2898 // there's at least six rows available, so we show the progress bar
2899 item.size.cy = height - ypos - 1;
2900 MoveWindow (item.hwnd, 2, ypos + 1, width - 2, item.size.cy, false) ;
2901 }
2902 else
2903 {
2904 // not enough room for progress bar: hide it
2905 ShowWindow(item.hwnd, SW_HIDE);
2906 }
2907 }
2908
SetStatusPanelItemText(int id,LPCSTR format,...)2909 void SetStatusPanelItemText (int id, LPCSTR format, ...)
2910 {
2911 char str [2048] ;
2912 va_list arg_ptr ;
2913
2914 va_start (arg_ptr, format) ;
2915 vsprintf (str, format, arg_ptr) ;
2916 va_end (arg_ptr) ;
2917 SetWindowText (StatusPanelItems [id].hwnd, str) ;
2918 }
2919
2920 /**************************************************************************************/
2921 /* WINDOW PROCEDURES */
2922 /**************************************************************************************/
2923
2924 /*
2925 * Return true if we are to return 0 to Windows, false if we are to continue.
2926 */
handle_main_command(WPARAM wParam,LPARAM lParam)2927 bool handle_main_command (WPARAM wParam, LPARAM lParam)
2928 {
2929 int n ;
2930 char *s ;
2931 char filename [_MAX_PATH] ;
2932 HDIB hDIB ;
2933 RECT rect ;
2934 BITMAP bm ;
2935 HBITMAP hBMP ;
2936 CHOOSECOLOR cc ;
2937 struct stat st ;
2938 static char str [8192] ;
2939 vfeWinSession& Session(GetSession());
2940
2941 if (process_toggles (wParam))
2942 return (true) ;
2943
2944 if (LOWORD (wParam) >= CM_FIRSTTOOL && LOWORD (wParam) <= CM_LASTTOOL)
2945 {
2946 s = parse_tool_command (tool_commands [LOWORD (wParam) - CM_FIRSTTOOL]) ;
2947 if (GetHKCU("General", "Debug", 0))
2948 message_printf ("Tool request - in '%s', out '%s'\n", tool_commands [LOWORD (wParam) - CM_FIRSTTOOL], s) ;
2949 else
2950 execute_tool (s) ;
2951 return (true) ;
2952 }
2953
2954 if (LOWORD (wParam) >= CM_FIRSTMENUHELP && LOWORD (wParam) <= CM_LASTMENUHELP)
2955 {
2956 menuhelp (LOWORD (wParam)) ;
2957 return (true) ;
2958 }
2959
2960 if (LOWORD (wParam) >= CM_DUTYCYCLE_10 && LOWORD (wParam) <= CM_DUTYCYCLE_100)
2961 {
2962 PVCheckMenuRadioItem (CM_DUTYCYCLE_10, CM_DUTYCYCLE_100, LOWORD (wParam)) ;
2963 Duty_Cycle = LOWORD (wParam) - CM_DUTYCYCLE_10 ;
2964 return (true) ;
2965 }
2966
2967 #ifdef RTR_SUPPORT
2968 if (LOWORD (wParam) >= CM_FIRSTVIDEOSOURCE && LOWORD (wParam) <= CM_LASTVIDEOSOURCE)
2969 {
2970 char str [256] ;
2971 MENUITEMINFO mi ;
2972
2973 mi.cbSize = sizeof (MENUITEMINFO) ;
2974 mi.fMask = MIIM_TYPE ;
2975 mi.dwTypeData = str ;
2976 mi.cch = sizeof (str) ;
2977 if (GetMenuItemInfo(hVidcapMenu, LOWORD (wParam), false, &mi))
2978 {
2979 PVCheckMenuRadioItem (CM_FIRSTVIDEOSOURCE, CM_LASTVIDEOSOURCE, LOWORD (wParam)) ;
2980 status_printf (StatusMessage, "Selected video source '%s'", str) ;
2981 SetVideoSourceName(str);
2982 }
2983 return (true) ;
2984 }
2985 #endif
2986
2987 if (LOWORD (wParam) >= CM_FIRSTEDITNOTIFY && LOWORD (wParam) <= CM_LASTEDITNOTIFY)
2988 {
2989 switch (LOWORD (wParam) - CM_FIRSTEDITNOTIFY)
2990 {
2991 case NotifyTabChange :
2992 if ((lParam & EDIT_MSG_SELECTED) == 0)
2993 {
2994 build_editor_menu (hMainMenu) ;
2995 PVEnableMenuItem (CM_FILESAVE, (lParam & EDIT_CURRENT_MODIFIED) ? MF_ENABLED : MF_GRAYED) ;
2996 PVEnableMenuItem (CM_FILECLOSE, MF_ENABLED) ;
2997 s = EditGetFilename(true) ;
2998 if (s != NULL && *s != '\0')
2999 {
3000 sprintf (str, rendersleep ? "POV-Ray (paused) - %s" : "POV-Ray - %s", s) ;
3001 SetCaption (str) ;
3002 }
3003 else
3004 SetCaption (rendersleep ? "POV-Ray for Windows (paused)" : "POV-Ray for Windows") ;
3005 }
3006 else
3007 {
3008 build_main_menu (hMainMenu, true) ;
3009 PVEnableMenuItem (CM_FILESAVE, MF_GRAYED) ;
3010 PVEnableMenuItem (CM_FILECLOSE, MF_GRAYED) ;
3011 SetCaption (rendersleep ? "POV-Ray for Windows (paused)" : "POV-Ray for Windows") ;
3012 }
3013 break ;
3014
3015 case NotifyModifiedChange :
3016 PVEnableMenuItem (CM_FILESAVE, lParam ? MF_ENABLED : MF_GRAYED) ;
3017 s = EditGetFilename(true) ;
3018 if (s != NULL && *s != '\0')
3019 {
3020 sprintf (str, rendersleep ? "POV-Ray (paused) - %s" : "POV-Ray - %s", s) ;
3021 SetCaption (str) ;
3022 }
3023 else
3024 SetCaption (rendersleep ? "POV-Ray for Windows (paused)" : "POV-Ray for Windows") ;
3025 break ;
3026
3027 case NotifyFocusSaveModified :
3028 FeatureNotify ("FocusSaveModified",
3029 "POV-Ray - Modified Files Auto-Saved",
3030 "Your modified files were automatically saved when you switched to another "
3031 "application. This is necessary for the Auto-Reload feature to work. If you "
3032 "do not want this to happen, turn auto-reload off via the Editor menu.\n\n"
3033 "Click Help for more information.",
3034 "auto-reload", false) ;
3035 break ;
3036
3037 case NotifyExitRequest :
3038 handle_main_command (CM_FILEEXIT, 0) ;
3039 break ;
3040 }
3041 return (true) ;
3042 }
3043
3044 switch (LOWORD (wParam))
3045 {
3046 case CM_HIDENEWUSERHELP :
3047 set_newuser_menus (hide_newuser_help) ;
3048 return (0) ;
3049
3050 case CM_IO_NO_RESTRICTIONS :
3051 case CM_IO_RESTRICT_WRITE :
3052 case CM_IO_RESTRICT_READWRITE :
3053 io_restrictions = LOWORD (wParam) - CM_IO_NO_RESTRICTIONS ;
3054 PVCheckMenuRadioItem (CM_IO_NO_RESTRICTIONS, CM_IO_RESTRICT_READWRITE, LOWORD (wParam)) ;
3055 PutHKCU ("Scripting", "IO Restrictions", io_restrictions) ;
3056 SetupFrontend();
3057 return (0) ;
3058
3059 case CM_SHOWMAINWINDOW :
3060 if (main_window_hidden)
3061 {
3062 if (ListenMode)
3063 {
3064 char *s = "POV-Ray is in network listen mode. Press OK to continue listening or "
3065 "CANCEL to shut down and exit." ;
3066 if (MessageBox (main_window, s, "POV-Ray - Network Listen Mode", MB_OKCANCEL) == IDOK)
3067 return (0) ;
3068 TaskBarDeleteIcon (main_window, 0) ;
3069 DestroyWindow (main_window) ;
3070 return (0) ;
3071 }
3072 ShowWindow (main_window, SW_SHOW) ;
3073 ShowWindow (main_window, SW_RESTORE) ;
3074 if (RenderwinIsChild == false && HideRenderWithMain == true)
3075 if (GetRenderWindow() != NULL)
3076 GetRenderWindow()->Show();
3077 PVModifyMenu (CM_SHOWMAINWINDOW, MF_STRING, CM_SHOWMAINWINDOW, "Minimize to System &Tray\tAlt+W") ;
3078 main_window_hidden = 0 ;
3079 TaskBarDeleteIcon (main_window, 0) ;
3080 }
3081 else
3082 {
3083 if (use_taskbar)
3084 {
3085 char *s = "POV-Ray (Restore: DblClk ; Menu: Mouse Btn 2)" ;
3086 if (ListenMode)
3087 s = "POV-Ray: Network Listen Mode - DblClick for Options" ;
3088 if (TaskBarAddIcon (main_window, 0, ourIcon, s))
3089 {
3090 ShowWindow (main_window, SW_MINIMIZE) ;
3091 ShowWindow (main_window, SW_HIDE) ;
3092 if (RenderwinIsChild == false && HideRenderWithMain == true)
3093 if (GetRenderWindow() != NULL)
3094 GetRenderWindow()->Hide();
3095 PVModifyMenu (CM_SHOWMAINWINDOW, MF_STRING, CM_SHOWMAINWINDOW, "Restore &Main Window from System Tray") ;
3096 main_window_hidden = true ;
3097 }
3098 }
3099 }
3100 return (0) ;
3101
3102 case CM_FILENEW :
3103 EditOpenFile (NULL) ;
3104 return (0) ;
3105
3106 case CM_FILEOPEN :
3107 EditBrowseFile (true) ;
3108 return (0) ;
3109
3110 case CM_FILESAVE :
3111 EditSaveFile (NULL) ;
3112 return (0) ;
3113
3114 case CM_FILECLOSE :
3115 EditCloseFile (NULL) ;
3116 return (0) ;
3117
3118 case CM_RENDERSLEEP :
3119 if (Session.BackendFailed())
3120 break ;
3121 if (!Session.IsPausable())
3122 break ;
3123 if (Session.Paused())
3124 {
3125 if (Session.Resume())
3126 {
3127 SetCaption ("POV-Ray for Windows") ;
3128 FlashWindow (main_window, 0) ;
3129 SleepTimeEnd = clock () ;
3130 SleepTimeTotal += SleepTimeEnd - SleepTimeStart ;
3131 say_status_message (StatusPPS, "") ;
3132 rendersleep = false ;
3133 SendMessage (toolbar_window, TB_CHECKBUTTON, (WPARAM) CM_RENDERSLEEP, 0) ;
3134 }
3135 else
3136 SendMessage (toolbar_window, TB_CHECKBUTTON, (WPARAM) CM_RENDERSLEEP, MAKELONG (1, 0)) ;
3137 }
3138 else
3139 if (Session.Pause () == false)
3140 SendMessage (toolbar_window, TB_CHECKBUTTON, (WPARAM) CM_RENDERSLEEP, 0) ;
3141 break ;
3142
3143 case CM_DROPEDITOR :
3144 case CM_DROPRENDERER :
3145 PVCheckMenuItem (CM_DROPEDITOR, LOWORD (wParam) == CM_DROPEDITOR ? MF_CHECKED : MF_UNCHECKED) ;
3146 PVCheckMenuItem (CM_DROPRENDERER, LOWORD (wParam) == CM_DROPRENDERER ? MF_CHECKED : MF_UNCHECKED) ;
3147 drop_to_editor = LOWORD (wParam) == CM_DROPEDITOR ;
3148 break ;
3149
3150 case CM_RENDERPRIORITY_BACKGROUND :
3151 case CM_RENDERPRIORITY_LOW :
3152 case CM_RENDERPRIORITY_NORMAL :
3153 case CM_RENDERPRIORITY_HIGH :
3154 render_priority = LOWORD (wParam) ;
3155 PVCheckMenuRadioItem (CM_RENDERPRIORITY_BACKGROUND, CM_RENDERPRIORITY_HIGH, render_priority) ;
3156 // only change process priority when the renderer is running
3157 if (rendering)
3158 set_render_priority (render_priority) ;
3159 return (true) ;
3160
3161 case CM_COMPLETION_EXIT :
3162 case CM_COMPLETION_NOTHING :
3163 case CM_COMPLETION_MESSAGE :
3164 PVCheckMenuItem (on_completion, MF_UNCHECKED) ;
3165 on_completion = LOWORD (wParam) ;
3166 PVCheckMenuItem (on_completion, MF_CHECKED) ;
3167 return (true) ;
3168
3169 case CM_PREVWINDOW :
3170 EditNextTab (false) ;
3171 return (true) ;
3172
3173 case CM_NEXTWINDOW :
3174 EditNextTab (true) ;
3175 return (true) ;
3176
3177 case CM_USETOOLBAR :
3178 if (rebar_window == NULL)
3179 return (true) ;
3180 ShowWindow (rebar_window, use_toolbar ? SW_SHOW : SW_HIDE) ;
3181 // this seems to be needed to get the rebar to redraw properly with v4.72 of comctrl32.dll.
3182 InvalidateRect (main_window, NULL, true) ;
3183 toolheight = 0 ;
3184 GetClientRect (main_window, &rect) ;
3185 SendMessage (main_window, WM_SIZE, SIZE_RESTORED, MAKELPARAM (rect.right, rect.bottom)) ;
3186 return (true) ;
3187
3188 case CM_SINGLEINSTANCE :
3189 PutHKCU ("General", "OneInstance", one_instance) ;
3190 return (true) ;
3191
3192 case CM_FILEEXIT :
3193 if (rendering)
3194 {
3195 if (MessageBox (main_window,
3196 "POV-Ray is currently rendering - do you want to stop ?",
3197 "Stop rendering ?",
3198 MB_ICONQUESTION | MB_YESNO) == IDYES)
3199 {
3200 if (!EditCanClose (true))
3201 return (true) ;
3202 if (!quit)
3203 quit = time (NULL) ;
3204 cancel_render () ;
3205 }
3206 }
3207 else
3208 {
3209 if (!EditCanClose (true))
3210 return (true) ;
3211 DestroyWindow (main_window) ;
3212 }
3213 return (true) ;
3214
3215 case CM_FILERENDER :
3216 case CM_STOPRENDER :
3217 if (Session.BackendFailed())
3218 return (true) ;
3219 if (!rendering)
3220 {
3221 if (EditSaveModified (NULL) == 0)
3222 return (true) ;
3223 // EDIT_MSG_SELECTED is only ever set if use_editors == true
3224 if ((EditGetFlags () & EDIT_MSG_SELECTED) == 0)
3225 {
3226 if ((s = EditGetFilename(false)) == NULL)
3227 {
3228 PovMessageBox ("No file to render in current editor tab!", "Cannot render") ;
3229 return (true) ;
3230 }
3231 n = get_file_type (s) ;
3232 if (n == filePOV || n == fileINI || !ExternalDragFunction (s, dfRenderEditor))
3233 PostMessage (main_window, EDITOR_RENDER_MESSAGE, 0, (LPARAM) s) ;
3234 return (true) ;
3235 }
3236 SetForegroundWindow (main_window) ;
3237 if (!ExternalDragFunction (source_file_name, dfRenderMessage))
3238 start_rendering (false) ;
3239 }
3240 else
3241 {
3242 if (Session.GetBackendState () >= kStopping)
3243 return (true) ;
3244 if (OkToStopRendering ())
3245 {
3246 if (rendersleep)
3247 {
3248 SleepTimeEnd = clock () ;
3249 SleepTimeTotal += SleepTimeEnd - SleepTimeStart ;
3250 rendersleep = false ;
3251 }
3252 stop_rendering = true ;
3253 cancel_render () ;
3254 }
3255 }
3256 return (true) ;
3257
3258 case CM_SAVE_SETTINGS :
3259 PutHKCU ("General", "SaveSettingsOnExit", save_settings) ;
3260 return (true) ;
3261
3262 case CM_DUMPPANE :
3263 dump_pane_to_clipboard () ;
3264 return (true) ;
3265
3266 case CM_CLEARMESSAGES :
3267 clear_messages () ;
3268 PovInvalidateRect (message_window, NULL, false) ;
3269 UpdateWindow (message_window) ;
3270 return (true) ;
3271
3272 case CM_FORCE8BITS :
3273 detect_graphics_config () ;
3274 if (hPalApp)
3275 DeleteObject (hPalApp) ;
3276 hPalApp = WinLegacyDisplay::CreatePalette (NULL, 0, render_bitmap_depth != 24) ;
3277 buffer_message (mIDE, render_bitmap_depth == 24 ? "Using 24-bit internal bitmap\n" :
3278 renderwin_8bits ? "Using 8-bit dithered internal bitmap (menu setting)\n" :
3279 "Using 8-bit dithered internal bitmap (4 or 8-bit video mode)\n") ;
3280 return (true) ;
3281
3282 case CM_RENDERABOVEMAIN :
3283 // TODO FIXME CJC
3284 #if 0
3285 // simply re-parenting doesn't seem to have the desired effect. sigh.
3286 WinDisplay *rw = GetRenderWindow();
3287 if (rw != NULL)
3288 {
3289 oldHwnd = render_window ;
3290 render_window = NULL ;
3291 ShowWindow (oldHwnd, SW_HIDE) ;
3292 SetForegroundWindow (main_window) ;
3293 DestroyWindow (oldHwnd) ;
3294 renderwin_manually_closed = false ;
3295 create_render_window (true) ;
3296 ShowWindow (render_window, SW_SHOW) ;
3297 }
3298 #endif
3299 PVEnableMenuItem (CM_RENDERHIDE, RenderwinIsChild ? MF_GRAYED : MF_ENABLED) ;
3300 PVEnableMenuItem (CM_RENDERACTIVE, RenderwinIsChild ? MF_GRAYED : MF_ENABLED) ;
3301 return (true) ;
3302
3303 case CM_USEEDITOR :
3304 editors_enabled = !editors_enabled;
3305 PutHKCU ("General", "UseEditors", editors_enabled) ;
3306 PVCheckMenuItem (CM_USEEDITOR, editors_enabled ? MF_CHECKED : MF_UNCHECKED) ;
3307 if (editors_enabled == use_editors)
3308 return true;
3309 if (MessageBox (main_window,
3310 "POV-Ray for Windows needs to re-start for this to take effect immediately.\n\n"
3311 "Re-start POV-Ray ?",
3312 "Re-start POV-Ray for Windows ?",
3313 MB_ICONEXCLAMATION | MB_YESNO) == IDYES)
3314 {
3315 GetModuleFileName (hInstance, filename, sizeof (filename) - 1) ;
3316 if (save_settings)
3317 {
3318 SendMessage (toolbar_combobox,
3319 CB_GETLBTEXT,
3320 SendMessage (toolbar_combobox, CB_GETCURSEL, 0, 0),
3321 (LPARAM) SecondaryRenderIniFileSection) ;
3322 if (restore_command_line)
3323 {
3324 strcpy (command_line, old_command_line) ;
3325 SendMessage (toolbar_cmdline, WM_SETTEXT, 0, (LPARAM) command_line) ;
3326 restore_command_line = false ;
3327 }
3328 write_INI_settings () ;
3329 EditSaveState () ;
3330 }
3331 DestroyWindow (main_window) ;
3332 execute_tool (filename) ;
3333 }
3334 return (true) ;
3335
3336 case CM_HELPABOUT :
3337 ShowAboutBox () ;
3338 return (true) ;
3339
3340 case CM_TOOLBARCMDLINE :
3341 if (!rendering)
3342 {
3343 SetFocus (toolbar_cmdline) ;
3344 SendMessage (toolbar_cmdline, EM_SETSEL, 0, -1) ;
3345 }
3346 return (true) ;
3347
3348 case CM_RENDERINSERT :
3349 if (!rendering)
3350 RenderInsertMenu () ;
3351 return (true) ;
3352
3353 case CM_COMMANDLINE :
3354 if (!rendering)
3355 {
3356 if (DialogBoxParam (hInstance,
3357 MAKEINTRESOURCE (IDD_COMMANDLINE),
3358 main_window,
3359 (DLGPROC) PovCommandLineDialogProc,
3360 (LPARAM) main_window))
3361 {
3362 if (!ExternalDragFunction (source_file_name, dfRenderCommandLine))
3363 start_rendering (false) ;
3364 }
3365 }
3366 return (true) ;
3367
3368 case CM_TILEDBACKGROUND :
3369 PVModifyMenu (CM_TILEDBACKGROUND, MF_STRING, CM_TILEDBACKGROUND, tile_background ? "&Use Plain Background" : "&Use Tiled Background") ;
3370 if (tile_background && hBmpBackground == NULL)
3371 {
3372 if ((hBmpBackground = NonBogusLoadBitmap (hInstance, MAKEINTRESOURCE (BMP_BACKGROUND00))) != NULL)
3373 {
3374 GetObject (hBmpBackground, sizeof (BITMAP), (LPSTR) &bm) ;
3375 background_width = bm.bmWidth ;
3376 background_height = bm.bmHeight ;
3377 tile_background = true ;
3378 PovInvalidateRect (message_window, NULL, true) ;
3379 }
3380 else
3381 {
3382 tile_background = false ;
3383 // make sure this messagebox is AFTER we set tile_background to false !
3384 PovMessageBox ("Failed to load internal bitmap", "Error") ;
3385 PVModifyMenu (CM_TILEDBACKGROUND, MF_STRING, CM_TILEDBACKGROUND, "&Select Tiled Background") ;
3386 background_file [0] = '\0' ;
3387 }
3388 return (true) ;
3389 }
3390 else
3391 PovInvalidateRect (message_window, NULL, true) ;
3392 return (true) ;
3393
3394 case CM_BACKGROUNDCOLOUR :
3395 memset (&cc, 0, sizeof (CHOOSECOLOR)) ;
3396 cc.lStructSize = sizeof (CHOOSECOLOR) ;
3397 cc.hwndOwner = main_window ;
3398 cc.rgbResult = background_colour ;
3399 cc.Flags = CC_RGBINIT | CC_FULLOPEN ;
3400 cc.lpCustColors = custom_colours ;
3401 if (ChooseColor (&cc))
3402 {
3403 background_colour = cc.rgbResult ;
3404 PovInvalidateRect (message_window, NULL, true) ;
3405 }
3406 return (true) ;
3407
3408 case CM_BACKGROUNDBITMAP :
3409 if ((s = get_background_file (main_window)) != NULL)
3410 {
3411 if ((hDIB = LoadDIB (s)) != NULL)
3412 {
3413 strcpy (background_file, s) ;
3414 DeleteObject (hBmpBackground) ;
3415 hBmpBackground = DIBToBitmap (hDIB, hPalApp) ;
3416 DeleteObject (hDIB) ;
3417 GetObject (hBmpBackground, sizeof (BITMAP), (LPSTR) &bm) ;
3418 background_width = bm.bmWidth ;
3419 background_height = bm.bmHeight ;
3420 tile_background = true ;
3421 PVModifyMenu (CM_TILEDBACKGROUND, MF_STRING, CM_TILEDBACKGROUND, "&Select Plain Background") ;
3422 background_shade = RGB (1, 1, 1) ;
3423 PovInvalidateRect (message_window, NULL, true) ;
3424 }
3425 else
3426 PovMessageBox ("Failed to load bitmap file", "Error") ;
3427 }
3428 return (true) ;
3429
3430 case CM_BACKGROUNDSTD + 0 :
3431 case CM_BACKGROUNDSTD + 1 :
3432 case CM_BACKGROUNDSTD + 2 :
3433 case CM_BACKGROUNDSTD + 3 :
3434 case CM_BACKGROUNDSTD + 4 :
3435 case CM_BACKGROUNDSTD + 5 :
3436 case CM_BACKGROUNDSTD + 6 :
3437 case CM_BACKGROUNDSTD + 7 :
3438 case CM_BACKGROUNDSTD + 8 :
3439 case CM_BACKGROUNDSTD + 9 :
3440 if ((hBMP = NonBogusLoadBitmap (hInstance, MAKEINTRESOURCE (BMP_BACKGROUND00 + (LOWORD (wParam) - CM_BACKGROUNDSTD)))) != NULL)
3441 {
3442 DeleteObject (hBmpBackground) ;
3443 hBmpBackground = hBMP ;
3444 if (GetObject (hBmpBackground, sizeof (BITMAP), (LPVOID) &bm) == 0)
3445 {
3446 PovMessageBox ("Failed to load internal bitmap", "Error") ;
3447 tile_background = false ;
3448 return (true) ;
3449 }
3450 background_width = bm.bmWidth ;
3451 background_height = bm.bmHeight ;
3452 background_file [0] = '0' + (char) (LOWORD (wParam) - CM_BACKGROUNDSTD) ;
3453 background_file [1] = '\0' ;
3454 switch (LOWORD (wParam))
3455 {
3456 case CM_BACKGROUNDSTD + 0 :
3457 background_shade = RGB (1, 1, 1) ;
3458 if (lParam != 1)
3459 text_colours[0] = RGB (255, 255, 255) ;
3460 break ;
3461
3462 case CM_BACKGROUNDSTD + 1 :
3463 background_shade = RGB (0, 0, 0) ;
3464 if (lParam != 1)
3465 text_colours[0] = RGB (255, 255, 255) ;
3466 break ;
3467
3468 case CM_BACKGROUNDSTD + 2 :
3469 background_shade = RGB (1, 1, 1) ;
3470 if (lParam != 1)
3471 text_colours[0] = RGB (255, 255, 255) ;
3472 break ;
3473
3474 case CM_BACKGROUNDSTD + 3 :
3475 background_shade = RGB (1, 1, 1) ;
3476 if (lParam != 1)
3477 text_colours[0] = RGB (255, 255, 255) ;
3478 break ;
3479
3480 case CM_BACKGROUNDSTD + 4 :
3481 background_shade = RGB (1, 1, 1) ;
3482 if (lParam != 1)
3483 text_colours[0] = RGB (255, 255, 255) ;
3484 break ;
3485
3486 case CM_BACKGROUNDSTD + 5 :
3487 background_shade = RGB (1, 1, 1) ;
3488 if (lParam != 1)
3489 text_colours[0] = RGB (0, 0, 0) ;
3490 break ;
3491 }
3492 tile_background = true ;
3493 PVModifyMenu (CM_TILEDBACKGROUND, MF_STRING, CM_TILEDBACKGROUND, "&Select Plain Background") ;
3494 PovInvalidateRect (message_window, NULL, true) ;
3495 }
3496 else
3497 PovMessageBox ("Failed to load internal bitmap", "Error") ;
3498 return (true) ;
3499
3500 case CM_TEXTCOLOUR_NORMAL :
3501 case CM_TEXTCOLOUR_WARNING :
3502 case CM_TEXTCOLOUR_ERROR :
3503 memset (&cc, 0, sizeof (CHOOSECOLOR)) ;
3504 cc.lStructSize = sizeof (CHOOSECOLOR) ;
3505 cc.hwndOwner = main_window ;
3506 cc.rgbResult = text_colours[LOWORD (wParam) - CM_TEXTCOLOUR_FIRST] ;
3507 cc.Flags = CC_RGBINIT | CC_FULLOPEN ;
3508 cc.lpCustColors = custom_colours ;
3509 if (ChooseColor (&cc))
3510 {
3511 text_colours[LOWORD (wParam) - CM_TEXTCOLOUR_FIRST] = cc.rgbResult ;
3512 PovInvalidateRect (message_window, NULL, true) ;
3513 }
3514 return (true) ;
3515
3516 case CM_FONT :
3517 get_font () ;
3518 return (true) ;
3519
3520 case CM_RENDERSHOW :
3521 if (GetRenderWindow() != NULL)
3522 {
3523 GetRenderWindow()->Show();
3524 PVEnableMenuItem (CM_RENDERSHOW, MF_GRAYED) ;
3525 PVEnableMenuItem (CM_RENDERCLOSE, MF_ENABLED) ;
3526 }
3527 return (true) ;
3528
3529 case CM_RENDERCLOSE :
3530 if (GetRenderWindow() != NULL)
3531 {
3532 if (GetForegroundWindow () == GetRenderwinHandle())
3533 if (RenderwinIsChild)
3534 SetForegroundWindow (main_window) ;
3535 GetRenderWindow()->Hide();
3536 PVEnableMenuItem (CM_RENDERSHOW, MF_ENABLED) ;
3537 PVEnableMenuItem (CM_RENDERCLOSE, MF_GRAYED) ;
3538 }
3539 return (true) ;
3540
3541 case CM_RENDERDESTROY :
3542 if (GetForegroundWindow () == (HWND) lParam)
3543 SetForegroundWindow (main_window) ;
3544 DestroyWindow ((HWND) lParam) ;
3545 return (true) ;
3546
3547 case CM_CLEARQUEUE :
3548 queued_file_count = 0 ;
3549 update_queue_status (true) ;
3550 return (true) ;
3551
3552 case CM_FILEQUEUE :
3553 DialogBoxParam (hInstance, MAKEINTRESOURCE (IDD_FILEQUEUE), main_window, (DLGPROC) PovFileQueueDialogProc, (LPARAM) main_window) ;
3554 return (true) ;
3555
3556 case CM_SOURCEFILE :
3557 if (!rendering)
3558 {
3559 if ((s = file_open (main_window)) != NULL)
3560 {
3561 strcpy (source_file_name, s) ;
3562 splitpath (source_file_name, lastRenderPath, lastRenderName) ;
3563 validatePath (lastRenderPath) ;
3564 if (!ExternalDragFunction (source_file_name, dfRenderSourceFile))
3565 start_rendering (false) ;
3566 }
3567 }
3568 return (true) ;
3569
3570 case CM_RENDERSOUNDS :
3571 hh_aklink.pszKeywords = "sounds" ;
3572 DialogBoxParam (hInstance, MAKEINTRESOURCE (IDD_SOUNDS), main_window, (DLGPROC) PovSoundsDialogProc, (LPARAM) main_window) ;
3573 return (true) ;
3574
3575 case CM_RENDERTHREADCOUNT :
3576 hh_aklink.pszKeywords = "thread count" ; // TODO
3577 DialogBoxParam (hInstance, MAKEINTRESOURCE (IDD_THREADS), main_window, (DLGPROC) PovThreadCountDialogProc, (LPARAM) main_window) ;
3578 return (true) ;
3579
3580 case CM_DEMO :
3581 if (!rendering && !running_demo)
3582 {
3583 if (save_demo_file (demo_file_name, demo_ini_name) != NULL)
3584 {
3585 if (!demo_mode)
3586 {
3587 running_demo = true ;
3588 if (DialogBoxParam (hInstance, MAKEINTRESOURCE (IDD_SHORTCOMMANDLINE), main_window, (DLGPROC) PovShortCommandLineDialogProc, (LPARAM) main_window))
3589 {
3590 if (!restore_command_line)
3591 strcpy (old_command_line, command_line) ;
3592 restore_command_line = true ;
3593 sprintf (command_line, "Include_Ini='%s' Input_File_Name='%s' ", demo_ini_name, demo_file_name) ;
3594 _strupr (command_line) ;
3595 strcat (command_line, old_command_line) ;
3596 ignore_auto_ini = true ;
3597 start_rendering (true) ;
3598 }
3599 }
3600 else
3601 {
3602 if (!restore_command_line)
3603 strcpy (old_command_line, command_line) ;
3604 restore_command_line = true ;
3605 sprintf (command_line, "Include_Ini='%s' Input_File_Name='%s' ", demo_ini_name, demo_file_name) ;
3606 running_demo = true ;
3607 start_rendering (true) ;
3608 }
3609 }
3610 }
3611 return (true) ;
3612
3613 case CM_BENCHMARK :
3614 case CM_BENCHMARKONETHREAD :
3615 if (rendering)
3616 return (0) ;
3617 if (!benchmark_mode)
3618 {
3619 n = Get_Benchmark_Version () ;
3620 hh_aklink.pszKeywords = "Run Benchmark" ;
3621 sprintf (str, "This command will run the standard POV-Ray benchmark version %x.%02x.\n", n / 256, n % 256) ;
3622 strcat (str, "This will take some time, and there will be no display or file output.\n\n") ;
3623 strcat (str, "Note that the benchmark has changed since v3.6 and cannot be compared with it.\n\n") ;
3624 if (LOWORD (wParam) == CM_BENCHMARK)
3625 {
3626 sprintf(str + strlen(str), "The benchmark will be rendered using %d threads. Continue?", ThreadCount) ;
3627 benchmark_multithread = true ;
3628 }
3629 else
3630 {
3631 strcat (str, "The benchmark will be rendered using a single thread. Continue?") ;
3632 benchmark_multithread = false ;
3633 }
3634 if (MessageBox (main_window, str, "Standard Benchmark", MB_YESNO | MB_ICONINFORMATION | MB_HELP) == IDNO)
3635 return (0) ;
3636 }
3637 GetTempPath (_MAX_PATH - 16, demo_file_name) ;
3638 appendPathSeparator(demo_file_name) ;
3639 strcpy (demo_ini_name, demo_file_name) ;
3640 strcat (demo_file_name, "POVBENCH.$$1") ;
3641 strcat (demo_ini_name, "POVBENCH.$$2") ;
3642 if (Write_Benchmark_File (demo_file_name, demo_ini_name))
3643 {
3644 running_benchmark = running_demo = true ;
3645 int threadCount = benchmark_mode || benchmark_multithread ? ThreadCount : 1 ;
3646 message_printf ("Running standard POV-Ray benchmark version %x.%02x using %d thread%s\n", n / 256, n % 256, threadCount, threadCount > 1 ? "s" : "") ;
3647 buffer_message (mDivider, "\n") ;
3648 status_printf (0, "Running standard POV-Ray benchmark version %x.%02x\n", n / 256, n % 256) ;
3649 start_rendering (true) ;
3650 }
3651 else
3652 PovMessageBox ("Failed to write temporary files", "Benchmark Failed") ;
3653 return (true) ;
3654
3655 case CM_LOADTOOLMENU :
3656 ExternalEvent (EventLoadToolMenu, 0) ;
3657 load_tool_menu (ToolIniFileName) ;
3658 break ;
3659
3660 case CM_HELPLOOKUP :
3661 if (GetFocus () == GetRenderwinHandle ())
3662 {
3663 hh_aklink.pszKeywords = "Render Window" ;
3664 HtmlHelp (NULL, engineHelpPath, HH_KEYWORD_LOOKUP, (DWORD_PTR) &hh_aklink) ;
3665 return (true) ;
3666 }
3667 if (GetFocus () == toolbar_cmdline)
3668 {
3669 hh_aklink.pszKeywords = "Toolbar Command Line" ;
3670 HtmlHelp (NULL, engineHelpPath, HH_KEYWORD_LOOKUP, (DWORD_PTR) &hh_aklink) ;
3671 return (true) ;
3672 }
3673 if (GetFocus () == toolbar_combobox)
3674 {
3675 hh_aklink.pszKeywords = "Preset Rendering Options" ;
3676 HtmlHelp (NULL, engineHelpPath, HH_KEYWORD_LOOKUP, (DWORD_PTR) &hh_aklink) ;
3677 return (true) ;
3678 }
3679 if ((EditGetFlags () & EDIT_MSG_SELECTED) != 0)
3680 HtmlHelp (NULL, engineHelpPath, HH_DISPLAY_TOC, 0) ;
3681 else
3682 EditContextHelp () ;
3683 return (true) ;
3684
3685 case CM_HELPPOVWIN :
3686 hh_aklink.pszKeywords = "welcome" ;
3687 HtmlHelp (NULL, engineHelpPath, HH_KEYWORD_LOOKUP, (DWORD_PTR) &hh_aklink) ;
3688 return (true) ;
3689
3690 case CM_HELPSCENE :
3691 hh_aklink.pszKeywords = "Scene Description Language" ;
3692 HtmlHelp (NULL, engineHelpPath, HH_KEYWORD_LOOKUP, (DWORD_PTR) &hh_aklink) ;
3693 return (true) ;
3694
3695 case CM_GOPOVRAYORG :
3696 ShellExecute (NULL, NULL, "http://www.povray.org/", NULL, NULL, SW_SHOWNORMAL) ;
3697 return (true) ;
3698
3699 case CM_HELPBUGS :
3700 hh_aklink.pszKeywords = "Bug Reports" ;
3701 HtmlHelp (NULL, engineHelpPath, HH_KEYWORD_LOOKUP, (DWORD_PTR) &hh_aklink) ;
3702 return (true) ;
3703
3704 case CM_POVLEGAL :
3705 if (stat (engineHelpPath, &st) == 0)
3706 {
3707 hh_aklink.pszKeywords = "POV-Ray License" ;
3708 if (HtmlHelp (main_window, engineHelpPath, HH_KEYWORD_LOOKUP, (DWORD_PTR) &hh_aklink))
3709 return (true) ;
3710 }
3711 DialogBoxParam (hInstance, MAKEINTRESOURCE (IDD_VIEW), main_window, (DLGPROC) PovLegalDialogProc, (LPARAM) main_window) ;
3712 return (true) ;
3713
3714 case CM_CHECKUPDATENOW:
3715 #if POV_RAY_IS_OFFICIAL == 1
3716 ManualUpdateCheck();
3717 #endif
3718 return true;
3719 }
3720 return (false) ;
3721 }
3722
PovMainWndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)3723 LRESULT CALLBACK PovMainWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3724 {
3725 int i ;
3726 char *s ;
3727 char str [4096] ;
3728 bool f ;
3729 HDC hdc ;
3730 RECT rect ;
3731 POINT pt ;
3732 NMHDR *nmh ;
3733 DWORD result = 0 ;
3734 HPALETTE oldPalette ;
3735 TOOLTIPTEXT *t ;
3736 COPYDATASTRUCT *cd ;
3737 vfeSession& Session (GetSession());
3738
3739 PROCESS_MEMORY_COUNTERS memInfo;
3740
3741 switch (message)
3742 {
3743 case WM_COPYDATA :
3744 cd = (COPYDATASTRUCT *) lParam ;
3745 if (cd->dwData == EDIT_FILE)
3746 {
3747 strncpy (str, (char *) cd->lpData, sizeof (str) - 1) ;
3748 str [sizeof (str) - 1] = '\0' ;
3749 if (EditGetFlags () & EDIT_CAN_OPEN)
3750 EditOpenFile (str) ;
3751 return (0) ;
3752 }
3753 if (cd->dwData == RENDER_FILE)
3754 {
3755 strncpy (str, (char *) cd->lpData, sizeof (str) - 1) ;
3756 str [sizeof (str) - 1] = '\0' ;
3757 if (rendering)
3758 return (0) ;
3759 strcpy (source_file_name, str) ;
3760 start_rendering (false) ;
3761 return (0) ;
3762 }
3763 return (1) ;
3764
3765 case COPY_COMMANDLINE_MESSAGE :
3766 command_line [sizeof (command_line) - 1] = '\0' ;
3767 strncpy (command_line, (LPCSTR) lParam, sizeof (command_line) - 1) ;
3768 SendMessage (toolbar_cmdline, WM_SETTEXT, 0, (LPARAM) command_line) ;
3769 SendMessage (toolbar_cmdline, EM_SETSEL, 0, strlen (command_line)) ;
3770 SetFocus (toolbar_cmdline) ;
3771 return (true) ;
3772
3773 case WM_HELP :
3774 // we expect that whatever routine caused the WM_HELP would have set up the keyword
3775 HtmlHelp (NULL, engineHelpPath, HH_KEYWORD_LOOKUP, (DWORD_PTR) &hh_aklink) ;
3776 return (true) ;
3777
3778 case KEYWORD_LOOKUP_MESSAGE :
3779 hh_aklink.pszKeywords = (LPCSTR) lParam ;
3780 if (strncmp (hh_aklink.pszKeywords, "oooo", 4) == 0)
3781 hh_aklink.pszKeywords = "" ;
3782 if (strncmp (hh_aklink.pszKeywords, "//", 2) == 0)
3783 hh_aklink.pszKeywords = "" ;
3784 HtmlHelp (NULL, engineHelpPath, HH_KEYWORD_LOOKUP, (DWORD_PTR) &hh_aklink) ;
3785 return (true) ;
3786
3787 case TASKBAR_NOTIFY_MESSAGE :
3788 if (lParam == WM_LBUTTONDBLCLK)
3789 {
3790 if (ListenMode)
3791 {
3792 char *s = "POV-Ray is in network listen mode. Press OK to continue listening or "
3793 "CANCEL to shut down and exit." ;
3794 if (MessageBox (main_window, s, "POV-Ray - Network Listen Mode", MB_OKCANCEL | MB_SYSTEMMODAL) == IDOK)
3795 return (0) ;
3796 TaskBarDeleteIcon (main_window, 0) ;
3797 DestroyWindow (main_window) ;
3798 return (0) ;
3799 }
3800 ShowWindow (main_window, SW_SHOW) ;
3801 ShowWindow (main_window, SW_RESTORE) ;
3802 if (RenderwinIsChild == false && HideRenderWithMain == true)
3803 if (GetRenderWindow() != NULL)
3804 GetRenderWindow()->Show();
3805 PVModifyMenu (CM_SHOWMAINWINDOW, MF_STRING, CM_SHOWMAINWINDOW, "Minimize to System &Tray\tAlt+W") ;
3806 main_window_hidden = 0 ;
3807 TaskBarDeleteIcon (main_window, 0) ;
3808 return (0) ;
3809 }
3810 if (lParam == WM_RBUTTONDOWN)
3811 {
3812 if (ListenMode)
3813 return (0) ;
3814 if (hPopupMenus != NULL)
3815 {
3816 GetCursorPos (&pt) ;
3817 SetForegroundWindow (main_window) ;
3818 TrackPopupMenu (GetSubMenu (hPopupMenus, 0), TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, 0, main_window, NULL) ;
3819 return (0) ;
3820 }
3821 }
3822 return (0) ;
3823
3824 case WM_ENTERSIZEMOVE :
3825 if (!IsW95UserInterface)
3826 break ;
3827 resizing = true ;
3828 break ;
3829
3830 case WM_EXITSIZEMOVE :
3831 if (!IsW95UserInterface)
3832 break ;
3833 resizing = false ;
3834 InvalidateRect (message_window, NULL, true) ;
3835 break ;
3836
3837 case WM_SETFOCUS :
3838 // After a dialog has been displayed, Windows will give the focus
3839 // back to our main window. We need to farm the focus off to whatever
3840 // window should have it. EditSetFocus () will handle this for us.
3841 EditSetFocus () ;
3842 return (0) ;
3843
3844 case EDITOR_RENDER_MESSAGE :
3845 if (rendering)
3846 {
3847 if (OkToStopRendering ())
3848 {
3849 stop_rendering = true ;
3850 cancel_render () ;
3851 }
3852 return (0) ;
3853 }
3854 strcpy (source_file_name, (char *) lParam) ;
3855 if (is_non_primary_file(source_file_name))
3856 {
3857 char fn[_MAX_PATH + 1];
3858
3859 strcpy(fn, source_file_name);
3860 _strlwr(fn);
3861
3862 // see if we have a previous decision recorded for this file.
3863 std::map<string, bool>::const_iterator altit = IncludeAlternateDecisionMap.find(fn);
3864 if (altit == IncludeAlternateDecisionMap.end() || altit->second == true)
3865 {
3866 // either there is no decision recorded, or the decision was 'yes'
3867 // in either case we need to find the alternate filename
3868 std::map<string, string>::const_iterator it = IncludeToSourceMap.find(fn);
3869 if (it != IncludeToSourceMap.end())
3870 {
3871 // we've found the alternate filename. do we need to ask the user about it?
3872 if (altit == IncludeAlternateDecisionMap.end())
3873 {
3874 // yes we do.
3875 switch (DialogBoxParam (hInstance, MAKEINTRESOURCE (IDD_RENDERALTERNATEFILE), main_window, (DLGPROC) RenderAlternativeFileDialogProc, (LPARAM) it->second.c_str()))
3876 {
3877 case IDYES:
3878 // record the decision
3879 IncludeAlternateDecisionMap.insert(std::pair<string, bool>(fn, true));
3880 strcpy(source_file_name, it->second.c_str());
3881 break;
3882
3883 case IDOK:
3884 // we don't record this decision
3885 strcpy(source_file_name, it->second.c_str());
3886 break;
3887
3888 case IDNO:
3889 // record the decision
3890 IncludeAlternateDecisionMap.insert(std::pair<string, bool>(fn, false));
3891 break;
3892
3893 case IDCANCEL:
3894 return (0) ;
3895 }
3896 }
3897 else
3898 strcpy(source_file_name, it->second.c_str());
3899 }
3900 }
3901 }
3902 splitpath (source_file_name, lastRenderPath, lastRenderName) ;
3903 if (!ExternalDragFunction (source_file_name, dfRenderEditor))
3904 start_rendering (false) ;
3905 return (0) ;
3906
3907 case CREATE_RENDERWIN_MESSAGE :
3908 if (dynamic_cast<WinDisplay *>(reinterpret_cast<WinDisplay *>(lParam)) != NULL)
3909 return (dynamic_cast<WinDisplay *>(reinterpret_cast<WinDisplay *>(lParam))->CreateRenderWindow());
3910 return (0) ;
3911
3912 case GUIEXT_CREATE_EDITOR :
3913 if (wParam == 0)
3914 {
3915 message_printf ("External application or GUIEXT sent zero-length wParam for GUIEXT_CREATE_EDITOR\n") ;
3916 return (0) ;
3917 }
3918 if (IsBadReadPtr ((void *) lParam, wParam + 1))
3919 {
3920 message_printf ("External application or GUIEXT sent bad paramstr address for GUIEXT_CREATE_EDITOR\n") ;
3921 return (0) ;
3922 }
3923 if (((char *) lParam) [wParam] != '\0')
3924 {
3925 message_printf ("External application or GUIEXT sent non-NULL terminated paramstr for GUIEXT_CREATE_EDITOR\n") ;
3926 return (0) ;
3927 }
3928 return (EditExternalOpenFile ((char *) lParam)) ;
3929
3930 case WM_NOTIFY :
3931 nmh = (NMHDR *) lParam ;
3932 if (nmh->hwndFrom == tab_window)
3933 {
3934 EditPassOnMessage (hwnd, message, wParam, lParam, &result) ;
3935 break ;
3936 }
3937 if (nmh->hwndFrom == rebar_window)
3938 {
3939 switch (nmh->code)
3940 {
3941 case RBN_HEIGHTCHANGE :
3942 if (!use_toolbar)
3943 break ;
3944 GetClientRect (rebar_window, &rect) ;
3945
3946 // under XP with comctrl v6 it has been noticed that this event will occur
3947 // when the main window is minimized, before the parent's WM_SIZE message
3948 // is received, and that the return value from GetClientRect () seems to
3949 // be rather strange (e.g. 0,0,202,0 where the actual height is about 75.)
3950 if (rect.right == rect.left)
3951 break ;
3952
3953 toolheight = rect.bottom ;
3954 CalculateClientWindows (true) ;
3955
3956 // need this due to an issue with Windows 95
3957 if (top_message_row)
3958 {
3959 ShowScrollBar (message_window, SB_VERT, false) ;
3960 ShowScrollBar (message_window, SB_VERT, true) ;
3961 }
3962 if (need_hscroll ())
3963 {
3964 ShowScrollBar (message_window, SB_HORZ, false) ;
3965 ShowScrollBar (message_window, SB_HORZ, true) ;
3966 }
3967 break ;
3968 }
3969 break ;
3970 }
3971 if (nmh->hwndFrom == StatusTooltip)
3972 {
3973 if (HandleStatusTooltip(nmh))
3974 return 0;
3975 break;
3976 }
3977 switch (nmh->code)
3978 {
3979 case TTN_NEEDTEXT :
3980 t = (TOOLTIPTEXT *) lParam ;
3981 if (use_tooltips == 0)
3982 {
3983 t->lpszText = NULL ;
3984 t->hinst = 0 ;
3985 break ;
3986 }
3987 t->hinst = hInstance ;
3988 t->lpszText = MAKEINTRESOURCE (t->hdr.idFrom) ;
3989 return (0) ;
3990 }
3991 break ;
3992
3993 case RENDER_MESSAGE :
3994 s = getCommandLine () ;
3995 if (rendering && (strlen (s) || wParam))
3996 {
3997 PovMessageBox ("Cannot accept new command - already rendering", "Warning") ;
3998 return (0) ;
3999 }
4000 if (main_window_hidden)
4001 {
4002 ShowWindow (main_window, SW_SHOW) ;
4003 ShowWindow (main_window, SW_RESTORE) ;
4004 if (RenderwinIsChild == false && HideRenderWithMain == true)
4005 if (GetRenderWindow() != NULL)
4006 GetRenderWindow()->Show();
4007 PVModifyMenu (CM_SHOWMAINWINDOW, MF_STRING, CM_SHOWMAINWINDOW, "Minimize to System &Tray\tAlt+W") ;
4008 main_window_hidden = 0 ;
4009 TaskBarDeleteIcon (main_window, 0) ;
4010 return (0) ;
4011 }
4012 if (wParam == 0)
4013 {
4014 if (strlen (s) == 0)
4015 return (0) ;
4016 if (!restore_command_line)
4017 strcpy (old_command_line, command_line) ;
4018 restore_command_line = true ;
4019 strcpy (command_line, s) ;
4020 start_rendering (true) ;
4021 strcpy (command_line, old_command_line) ;
4022 SendMessage (toolbar_cmdline, WM_SETTEXT, 0, (LPARAM) command_line) ;
4023 restore_command_line = false ;
4024 }
4025 else
4026 handle_main_command (CM_DEMO, 0) ;
4027 return (0) ;
4028
4029 case WM_CREATE :
4030 main_window = hwnd ;
4031 hMainMenu = CreateMenu () ;
4032 build_main_menu (hMainMenu, false) ;
4033 SetMenu (main_window, hMainMenu) ;
4034 break ;
4035
4036 case WM_QUERYENDSESSION :
4037 if (rendering)
4038 {
4039 if (MessageBox (main_window, "POV-Ray is currently rendering - do you want to stop ?", "Stop rendering ?", MB_ICONQUESTION | MB_YESNO) != IDYES)
4040 return (false) ;
4041 if (!EditCanClose (true))
4042 return (false) ;
4043 if (!quit)
4044 quit = time (NULL) ;
4045 cancel_render () ;
4046 return (true) ;
4047 }
4048 return (EditCanClose (true)) ;
4049
4050 case WM_ENDSESSION :
4051 if (wParam != 0)
4052 {
4053 setRunOnce () ;
4054 if (save_settings)
4055 {
4056 SendMessage (toolbar_combobox, CB_GETLBTEXT, SendMessage (toolbar_combobox, CB_GETCURSEL, 0, 0), (LPARAM) SecondaryRenderIniFileSection) ;
4057 if (restore_command_line)
4058 {
4059 strcpy (command_line, old_command_line) ;
4060 SendMessage (toolbar_cmdline, WM_SETTEXT, 0, (LPARAM) command_line) ;
4061 restore_command_line = false ;
4062 }
4063 write_INI_settings () ;
4064 EditSaveState () ;
4065 }
4066 }
4067 break ;
4068
4069 case WM_COMMAND :
4070 if ((HANDLE) lParam == toolbar_cmdline)
4071 {
4072 // need to use EN_CHANGE rather than EN_KILLFOCUS as the command-line dialog
4073 // will grab and possibly modify command_line before focus is lost, should it
4074 // be activated while the edit control has focus.
4075 if (HIWORD (wParam) == EN_CHANGE)
4076 {
4077 SendMessage (toolbar_cmdline, WM_GETTEXT, sizeof (command_line) - 1, (LPARAM) command_line) ;
4078 return (0) ;
4079 }
4080 }
4081 if ((HANDLE) lParam == toolbar_combobox)
4082 {
4083 if (HIWORD (wParam) == CBN_CLOSEUP)
4084 {
4085 cb_expect_selchange++ ;
4086 return (0) ;
4087 }
4088 if (HIWORD (wParam) == CBN_SELCHANGE)
4089 {
4090 i = SendMessage (toolbar_combobox, CB_GETCURSEL, 0, 0) ;
4091 if (i == SendMessage (toolbar_combobox, CB_GETCOUNT, 0, 0) - 1)
4092 {
4093 SendMessage (toolbar_combobox, CB_SETCURSEL, tb_combo_sel, 0) ;
4094 if (cb_expect_selchange)
4095 {
4096 hh_aklink.pszKeywords = "Adding New Resolutions" ;
4097 HtmlHelp (NULL, engineHelpPath, HH_KEYWORD_LOOKUP, (DWORD_PTR) &hh_aklink) ;
4098 }
4099 }
4100 else
4101 tb_combo_sel = i ;
4102 cb_expect_selchange = 0 ;
4103 return (0) ;
4104 }
4105 }
4106 if (EditPassOnMessage (hwnd, message, wParam, lParam, &result))
4107 return (result) ;
4108 if (ExtensionsEnabled)
4109 if (LOWORD (wParam) >= CM_FIRSTGUIEXT && LOWORD (wParam) <= CM_LASTGUIEXT)
4110 return (ExternalMenuSelect (LOWORD (wParam))) ;
4111 if (handle_main_command (wParam, lParam))
4112 return (0) ;
4113 break ;
4114
4115 case WM_INITMENU :
4116 EditUpdateMenus ((HMENU) wParam) ;
4117 EditPassOnMessage (hwnd, message, wParam, lParam, &result) ;
4118 break ;
4119
4120 case WM_ACTIVATEAPP :
4121 EditPassOnMessage (hwnd, message, wParam, lParam, &result) ;
4122 break ;
4123
4124 case WM_TIMER :
4125 if (!BackendFailedFlag && Session.BackendFailed())
4126 {
4127 BackendFailedFlag = true;
4128 if (rendering)
4129 {
4130 rendering = false;
4131 update_menu_for_render (false) ;
4132 PVEnableMenuItem (CM_FILERENDER, MF_DISABLED) ;
4133 PVEnableMenuItem (CM_STOPRENDER, MF_DISABLED) ;
4134 SendMessage (toolbar_window, TB_HIDEBUTTON, (WPARAM) CM_FILERENDER, MAKELONG (0, 0)) ;
4135 SendMessage (toolbar_window, TB_HIDEBUTTON, (WPARAM) CM_STOPRENDER, MAKELONG (0, 0)) ;
4136 status_buffer [0] = '\0' ;
4137 say_status_message (StatusMessage, "Render backend Failed - please re-start POV-Ray");
4138 delay_next_status = 2500;
4139 buffer_message (mFatal, "Render backend Failed - please re-start POV-Ray\n") ;
4140 if (render_complete_sound_enabled)
4141 PlaySound (render_error_sound, NULL, SND_ASYNC | SND_NODEFAULT) ;
4142 }
4143 }
4144 if (rendering && !Session.BackendFailed() && Session.GetPercentComplete() != LastRenderPercentage)
4145 {
4146 LastRenderPercentage = Session.GetPercentComplete();
4147 if (GetRenderWindow() != NULL)
4148 {
4149 sprintf (str, "%d%% complete", LastRenderPercentage) ;
4150 GetRenderWindow()->SetCaption(str);
4151 }
4152 if (main_window_hidden)
4153 {
4154 sprintf (str, "POV-Ray [%d%% complete] (Restore: DblClk ; Menu: Mouse2)", LastRenderPercentage) ;
4155 TaskBarModifyIcon (main_window, 0, str) ;
4156 }
4157 SendMessage (StatusPanelItems [IDC_STATUS_PROGRESS].hwnd, PBM_SETPOS, (WPARAM) LastRenderPercentage, 0) ;
4158 SetCaption (NULL) ;
4159 }
4160 if (delay_next_status)
4161 {
4162 delay_next_status -= 250 ;
4163 if (delay_next_status < 0)
4164 delay_next_status = 0 ;
4165 }
4166 if (status_buffer [0] != '\0' && delay_next_status == 0)
4167 {
4168 say_status_message (StatusMessage, status_buffer) ;
4169 status_buffer [0] = '\0' ;
4170 }
4171
4172 memInfo.cb = sizeof(memInfo);
4173 GetProcessMemoryInfo(GetCurrentProcess(), &memInfo, sizeof(memInfo));
4174 status_printf(StatusMem, "\t%uMB", (unsigned int) (memInfo.WorkingSetSize / 1048576));
4175 if (TrackMem && memInfo.WorkingSetSize > PeakMem)
4176 PeakMem = memInfo.WorkingSetSize;
4177
4178 // NOTE: if we ever change the timer rate, we need to update the editor code too.
4179 EditPassOnMessage (hwnd, message, wParam, lParam, &result) ;
4180 if (timer_ticks++ % 4 != 3)
4181 break ;
4182 seconds++ ;
4183
4184 #if POV_RAY_IS_OFFICIAL == 1
4185 if (seconds % 600 == 0)
4186 DoUpdateCheck () ;
4187 #endif
4188
4189 ExternalEvent (EventTimer, seconds) ;
4190 if (MenuBarDraw)
4191 {
4192 DrawMenuBar (main_window) ;
4193 MenuBarDraw = false ;
4194 }
4195 if (!rendering)
4196 {
4197 if (auto_render)
4198 {
4199 if (queued_file_count)
4200 {
4201 queued_file_count-- ;
4202 update_queue_status (true) ;
4203 strcpy (source_file_name, queued_files [0]) ;
4204 memcpy (queued_files [0], queued_files [1], sizeof (queued_files) - sizeof (queued_files [0])) ;
4205 splitpath (source_file_name, dir, NULL) ;
4206 SetCurrentDirectory (dir) ;
4207 if (seconds < 60 && GetHKCU("Info", "Rendering", 0) != 0)
4208 {
4209 // don't run the file if we were rendering when POV exited.
4210 // [Rendering should only be set if there was an abnormal exit.]
4211 PutHKCU ("Info", "Rendering", 0U) ;
4212 message_printf ("Skipping queued file '%s' (possible abnormal exit)\n", source_file_name) ;
4213 buffer_message (mDivider, "\n") ;
4214 }
4215 else
4216 if (!ExternalDragFunction (source_file_name, dfRenderFileQueue))
4217 start_rendering (false) ;
4218 }
4219 }
4220 }
4221 else
4222 {
4223 PrintRenderTimes (false, false) ;
4224 if (seconds % 10 == 0)
4225 {
4226 if (PreventSleep && !rendersleep)
4227 SetThreadExecutionState(ES_AWAYMODE_REQUIRED | ES_SYSTEM_REQUIRED);
4228 if (rendersleep)
4229 FlashWindow (main_window, true) ;
4230 }
4231 }
4232 return (0) ;
4233
4234 case WM_PALETTECHANGED :
4235 // make sure it wasn't us who changed the palette, otherwise we can get into an infinite loop.
4236 if ((HWND) wParam == main_window)
4237 return (0) ;
4238 // FALL THROUGH to WM_QUERYNEWPALETTE
4239
4240 case WM_QUERYNEWPALETTE :
4241 if (hPalApp)
4242 {
4243 hdc = GetDC (main_window) ;
4244 oldPalette = SelectPalette (hdc, hPalApp, false) ;
4245 f = (RealizePalette (hdc) != 0);
4246 SelectPalette (hdc, oldPalette, false) ;
4247 ReleaseDC (main_window, hdc) ;
4248 if (f)
4249 {
4250 PovInvalidateRect (hwnd, NULL, true) ;
4251 if ((EditGetFlags () & EDIT_MSG_SELECTED) == 0)
4252 PovInvalidateRect (message_window, NULL, true) ;
4253 if (GetRenderwinHandle() != NULL)
4254 PovInvalidateRect (GetRenderwinHandle(), NULL, true) ;
4255 }
4256 }
4257 return (0) ;
4258
4259 case WM_SIZE :
4260 if (main_window_hidden)
4261 {
4262 // perhaps another process has sent us a SIZE_RESTORED or something
4263 if (GetRenderWindow() != NULL)
4264 if (RenderwinIsChild == false && HideRenderWithMain == true)
4265 GetRenderWindow()->Show();
4266 PVModifyMenu (CM_SHOWMAINWINDOW, MF_STRING, CM_SHOWMAINWINDOW, "Minimize to System &Tray\tAlt+W") ;
4267 main_window_hidden = 0 ;
4268 TaskBarDeleteIcon (main_window, 0) ;
4269 }
4270 mainwin_placement.length = sizeof (WINDOWPLACEMENT) ;
4271 GetWindowPlacement (main_window, &mainwin_placement) ;
4272 SendMessage (rebar_window, WM_SIZE, wParam, lParam) ;
4273 SendMessage (StatusWindow, WM_SIZE, wParam, lParam) ;
4274 ResizeStatusBar (StatusWindow) ;
4275 switch (wParam)
4276 {
4277 case SIZE_MINIMIZED :
4278 SetCaption (rendersleep ? "POV-Ray for Windows (paused)" : "POV-Ray for Windows") ;
4279 if (GetRenderWindow() != NULL)
4280 if (RenderwinIsChild == false && HideRenderWithMain == true)
4281 GetRenderWindow()->Hide();
4282 ExternalEvent (EventSize, wParam) ;
4283 return (0) ;
4284
4285 case SIZE_RESTORED :
4286 SendMessage (StatusWindow, WM_SIZE, wParam, lParam) ;
4287 s = EditGetFilename(true) ;
4288 if (s != NULL && *s != '\0')
4289 {
4290 sprintf (str, rendersleep ? "POV-Ray (paused) - %s" : "POV-Ray - %s", s) ;
4291 SetCaption (str) ;
4292 }
4293 else
4294 SetCaption (rendersleep ? "POV-Ray for Windows (paused)" : "POV-Ray for Windows") ;
4295 // ***** fall through *****
4296
4297 case SIZE_MAXIMIZED :
4298 if (GetRenderwinHandle() != NULL)
4299 if (RenderwinIsChild == false && HideRenderWithMain == true)
4300 ShowWindow (GetRenderwinHandle(), MakeRenderwinActive ? SW_SHOW : SW_SHOWNA) ;
4301 SendMessage (toolbar_window, TB_AUTOSIZE, 0, 0) ;
4302 if (use_toolbar && rebar_window != NULL)
4303 {
4304 GetClientRect (rebar_window, &rect) ;
4305 toolheight = rect.bottom ;
4306 }
4307 CalculateClientWindows (true) ;
4308
4309 // need this due to an issue with Windows 95
4310 if (top_message_row)
4311 {
4312 ShowScrollBar (message_window, SB_VERT, false) ;
4313 ShowScrollBar (message_window, SB_VERT, true) ;
4314 }
4315 if (need_hscroll ())
4316 {
4317 ShowScrollBar (message_window, SB_HORZ, false) ;
4318 ShowScrollBar (message_window, SB_HORZ, true) ;
4319 }
4320 ExternalEvent (EventSize, wParam) ;
4321 break ;
4322
4323 case SIZE_MAXHIDE :
4324 case SIZE_MAXSHOW :
4325 default :
4326 ExternalEvent (EventSize, wParam) ;
4327 return (0) ;
4328 }
4329 return (0) ;
4330
4331 case WM_MOVE :
4332 mainwin_placement.length = sizeof (WINDOWPLACEMENT) ;
4333 GetWindowPlacement (main_window, &mainwin_placement) ;
4334 ExternalEvent (EventMove, lParam) ;
4335 return (0) ;
4336
4337 case WM_ERASEBKGND :
4338 if (IsIconic (main_window))
4339 {
4340 BitBlt ((HDC) wParam, 0, 0, 36, 36, NULL, 0, 0, BLACKNESS) ;
4341 return (1) ;
4342 }
4343 break ;
4344
4345 case WM_DROPFILES :
4346 DragFunction ((HDROP) wParam) ;
4347 return (0) ;
4348
4349 case WM_CHAR :
4350 switch ((char) wParam)
4351 {
4352 case 0x0f : // ctrl-o
4353 EditBrowseFile (true) ;
4354 return (0) ;
4355
4356 case 0x0e : // ctrl-n (close enough to shift-ctrl-n ;)
4357 EditOpenFile (NULL) ;
4358 return (0) ;
4359 }
4360 if (EditPassOnMessage (hwnd, message, wParam, lParam, &result))
4361 return (0) ;
4362 break ;
4363
4364 case WM_KEYDOWN :
4365 for (i = 0 ; key2scroll [i].wVirtkey != 0xffff ; i++)
4366 {
4367 if (wParam == key2scroll [i].wVirtkey)
4368 {
4369 SendMessage (message_window, key2scroll [i].iMessage, key2scroll [i].wRequest, 0L) ;
4370 return (0) ;
4371 }
4372 }
4373 break ;
4374
4375 case WM_MENUSELECT :
4376 if (EditPassOnMessage (hwnd, message, wParam, lParam, &result))
4377 return (result) ;
4378 handle_menu_select (wParam, lParam) ;
4379 return (0) ;
4380
4381 case WM_SHOWWINDOW :
4382 break ;
4383
4384 case WM_CLOSE :
4385 if (debugging)
4386 message_printf ("Close requested, rendering is %d, quit is %u\n", rendering, quit) ;
4387 if (rendering && !quit)
4388 {
4389 if (MessageBox (main_window,
4390 "POV-Ray is currently rendering - do you want to stop ?",
4391 "Stop rendering",
4392 MB_ICONQUESTION | MB_YESNO) == IDNO)
4393 {
4394 if (debugging)
4395 message_printf ("User tells us we can't close\n") ;
4396 return (0) ;
4397 }
4398 }
4399 if (!EditCanClose (true))
4400 {
4401 if (debugging)
4402 message_printf ("Editor tells us we can't close\n") ;
4403 return (0) ;
4404 }
4405 ExternalEvent (EventClose, 0) ;
4406 if (timer_id != 0)
4407 KillTimer (main_window, timer_id) ;
4408 DragAcceptFiles (main_window, false) ;
4409 if (!rendering || quit)
4410 {
4411 DestroyWindow (main_window) ;
4412 }
4413 else
4414 {
4415 if (!quit)
4416 quit = time (NULL) ;
4417 cancel_render () ;
4418 }
4419 return (0) ;
4420
4421 case WM_DESTROY :
4422 if (debugging)
4423 message_printf ("Destroy requested, rendering is %d, quit is %u\n", rendering, quit) ;
4424 if (!quit)
4425 {
4426 quit = time (NULL) ;
4427 if (rendering)
4428 cancel_render () ;
4429 }
4430 ExternalEvent (EventDestroy, 0) ;
4431 if (save_settings)
4432 {
4433 SendMessage (toolbar_combobox, CB_GETLBTEXT, SendMessage (toolbar_combobox, CB_GETCURSEL, 0, 0), (LPARAM) SecondaryRenderIniFileSection) ;
4434 if (restore_command_line)
4435 {
4436 strcpy (command_line, old_command_line) ;
4437 SendMessage (toolbar_cmdline, WM_SETTEXT, 0, (LPARAM) command_line) ;
4438 restore_command_line = false ;
4439 }
4440 write_INI_settings () ;
4441 EditSaveState () ;
4442 }
4443 PostQuitMessage (0) ;
4444 return (0) ;
4445 }
4446
4447 return (DefWindowProc (hwnd, message, wParam, lParam)) ;
4448 }
4449
PovMessageWndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)4450 LRESULT CALLBACK PovMessageWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4451 {
4452 int nhs ;
4453 int msg ;
4454 int mousewheel ;
4455 HDC hdc ;
4456 RECT rect ;
4457 POINT pt ;
4458 PAINTSTRUCT ps ;
4459 static bool captured = false ;
4460 static POINT mbdownPoint ;
4461
4462 switch (message)
4463 {
4464 case WM_MOUSEWHEEL :
4465 mousewheel = (short) (wParam >> 16) / WHEEL_DELTA ;
4466 if ((LOWORD (wParam) & (MK_MBUTTON | MK_CONTROL)) == 0)
4467 {
4468 msg = mousewheel < 0 ? SB_LINEDOWN : SB_LINEUP ;
4469 mousewheel *= 3 ;
4470 }
4471 else
4472 msg = mousewheel < 0 ? SB_PAGEDOWN : SB_PAGEUP ;
4473 mousewheel = abs (mousewheel) ;
4474 while (mousewheel--)
4475 PovMessageWndProc (hwnd, WM_VSCROLL, msg, 0) ;
4476 return (0) ;
4477
4478 case WM_KEYDOWN :
4479 PostMessage (main_window, message, wParam, lParam) ;
4480 return (0) ;
4481
4482 case WM_LBUTTONDOWN :
4483 SetCapture (hwnd) ;
4484 captured = true ;
4485 GetCursorPos (&mbdownPoint) ;
4486 return (0) ;
4487
4488 case WM_LBUTTONUP :
4489 if (!captured)
4490 return (0) ;
4491 ReleaseCapture () ;
4492 captured = false ;
4493 GetCursorPos (&pt) ;
4494 GetWindowRect (hwnd, &rect) ;
4495 if (pt.x < rect.left || pt.y < rect.top || pt.x > rect.right || pt.y > rect.bottom)
4496 return (0) ;
4497 if (abs (mbdownPoint.x - pt.x) > 3 || abs (mbdownPoint.y - pt.y) > 3)
4498 {
4499 hh_aklink.pszKeywords = "text streams" ;
4500 MessageBox (hwnd,
4501 "You may use the Edit menu to copy the contents of this message pane to the clipboard\n\n"
4502 "Press Help to learn how to direct the POV-Ray text output streams to a file",
4503 "Text Selection Not Supported In This Window",
4504 MB_OK | MB_ICONINFORMATION | MB_HELP) ;
4505 }
4506 return (0) ;
4507
4508 case WM_RBUTTONDOWN :
4509 if (hPopupMenus != NULL)
4510 {
4511 pt.x = LOWORD (lParam) ;
4512 pt.y = HIWORD (lParam) ;
4513 ClientToScreen (hwnd, &pt) ;
4514 TrackPopupMenu (GetSubMenu (hPopupMenus, 0),
4515 TPM_LEFTALIGN | TPM_RIGHTBUTTON,
4516 pt.x,
4517 pt.y,
4518 0,
4519 main_window,
4520 NULL) ;
4521 }
4522 return (0) ;
4523
4524 case WM_ERASEBKGND :
4525 return (1) ;
4526
4527 case WM_PAINT :
4528 hdc = BeginPaint (hwnd, &ps) ;
4529 if (hPalApp)
4530 {
4531 SelectPalette (hdc, hPalApp, false) ;
4532 RealizePalette (hdc) ;
4533 }
4534 paint_display_window (hdc) ;
4535 EndPaint (hwnd, &ps) ;
4536 return (0) ;
4537
4538 case WM_SIZE :
4539 if (message_count)
4540 {
4541 GetClientRect (hwnd, &rect) ;
4542 message_scroll_pos_x = 0 ;
4543 message_scroll_pos_y = message_count - rect.bottom / message_ychar ;
4544 if (message_scroll_pos_y < 0)
4545 message_scroll_pos_y = 0 ;
4546 }
4547 update_message_display (None) ;
4548 PovInvalidateRect (hwnd, NULL, true) ;
4549 return (0) ;
4550
4551 case WM_VSCROLL :
4552 switch (LOWORD (wParam))
4553 {
4554 case SB_LINEDOWN :
4555 if (message_scroll_pos_y < message_count - message_rows)
4556 {
4557 message_scroll_pos_y++ ;
4558 ScrollWindow (hwnd, 0, -message_ychar, NULL, NULL) ;
4559 update_message_display (None) ;
4560 UpdateWindow (hwnd) ;
4561 }
4562 break ;
4563
4564 case SB_LINEUP :
4565 if (message_scroll_pos_y > 0)
4566 {
4567 message_scroll_pos_y-- ;
4568 ScrollWindow (hwnd, 0, message_ychar, NULL, NULL) ;
4569 update_message_display (None) ;
4570 UpdateWindow (hwnd) ;
4571 }
4572 break ;
4573
4574 case SB_PAGEDOWN :
4575 if (message_scroll_pos_y < message_count - message_rows)
4576 {
4577 message_scroll_pos_y += message_rows ;
4578 if (message_scroll_pos_y > message_count - message_rows)
4579 message_scroll_pos_y = message_count - message_rows ;
4580 PovInvalidateRect (hwnd, NULL, true) ;
4581 update_message_display (None) ;
4582 }
4583 break ;
4584
4585 case SB_PAGEUP :
4586 if (message_scroll_pos_y > 0)
4587 {
4588 message_scroll_pos_y -= message_rows ;
4589 if (message_scroll_pos_y < 0)
4590 message_scroll_pos_y = 0 ;
4591 PovInvalidateRect (hwnd, NULL, true) ;
4592 update_message_display (None) ;
4593 }
4594 break ;
4595
4596 case SB_THUMBPOSITION :
4597 case SB_THUMBTRACK :
4598 message_scroll_pos_y = HIWORD (wParam) ;
4599 PovInvalidateRect (hwnd, NULL, true) ;
4600 update_message_display (None) ;
4601 break ;
4602 }
4603 return (0) ;
4604
4605 case WM_HSCROLL :
4606 nhs = need_hscroll () ;
4607 switch (LOWORD (wParam))
4608 {
4609 case SB_LINERIGHT :
4610 if (message_scroll_pos_x < nhs)
4611 {
4612 message_scroll_pos_x++ ;
4613 ScrollWindow (hwnd, -message_xchar, 0, NULL, NULL) ;
4614 update_message_display (None) ;
4615 UpdateWindow (hwnd) ;
4616 }
4617 break ;
4618
4619 case SB_LINELEFT :
4620 if (message_scroll_pos_x > 0)
4621 {
4622 message_scroll_pos_x-- ;
4623 ScrollWindow (hwnd, message_xchar, 0, NULL, NULL) ;
4624 update_message_display (None) ;
4625 UpdateWindow (hwnd) ;
4626 }
4627 break ;
4628
4629 case SB_PAGERIGHT :
4630 if (message_scroll_pos_x < nhs)
4631 {
4632 message_scroll_pos_x += message_cols ;
4633 if (message_scroll_pos_x > nhs)
4634 message_scroll_pos_x = nhs ;
4635 PovInvalidateRect (hwnd, NULL, true) ;
4636 update_message_display (None) ;
4637 }
4638 break ;
4639
4640 case SB_PAGELEFT :
4641 if (message_scroll_pos_x > 0)
4642 {
4643 message_scroll_pos_x -= message_cols ;
4644 if (message_scroll_pos_x < 0)
4645 message_scroll_pos_x = 0 ;
4646 PovInvalidateRect (hwnd, NULL, true) ;
4647 update_message_display (None) ;
4648 }
4649 break ;
4650
4651 case SB_THUMBPOSITION :
4652 case SB_THUMBTRACK :
4653 message_scroll_pos_x = HIWORD (wParam) ;
4654 PovInvalidateRect (hwnd, NULL, true) ;
4655 update_message_display (None) ;
4656 break ;
4657 }
4658 return (0) ;
4659 }
4660 return (DefWindowProc (hwnd, message, wParam, lParam)) ;
4661 }
4662
PovStatusPanelDialogProc(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam)4663 INT_PTR CALLBACK PovStatusPanelDialogProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
4664 {
4665 switch (message)
4666 {
4667 case WM_INITDIALOG :
4668 MoveWindow (hDlg, 0, 0, 204, 41, false) ;
4669 SetupStatusPanel (hDlg) ;
4670 SetStatusPanelItemText (IDC_STATUS_DATA_FRAME, "N/A") ;
4671 return (false) ;
4672 }
4673 return (false) ;
4674 }
4675
PovAboutWndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)4676 LRESULT CALLBACK PovAboutWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4677 {
4678 int button;
4679 int offset = 0;
4680 int i;
4681 HDC hdc ;
4682 HDC hdcMemory ;
4683 bool f ;
4684 DWORD threadId = 0 ;
4685 DWORD threadParam = 0 ;
4686 POINT pt;
4687 HBITMAP oldBmp ;
4688 HPALETTE oldPalette ;
4689 PAINTSTRUCT ps ;
4690 struct stat st ;
4691 LPDRAWITEMSTRUCT lpdis ;
4692 static char *url = NULL;
4693
4694 switch (message)
4695 {
4696 case WM_CREATE :
4697 about_showing = true ;
4698 url = NULL;
4699 break ;
4700
4701 case WM_DESTROY :
4702 about_showing = false ;
4703 EnableWindow (main_window, TRUE) ;
4704 DeleteObject (hBmpAbout) ;
4705 if (about_palette)
4706 {
4707 DeleteObject (about_palette) ;
4708 about_palette = NULL ;
4709 }
4710 hBmpAbout = NULL ;
4711 break ;
4712
4713 case WM_MOUSEMOVE:
4714 pt.x = LOWORD (lParam);
4715 pt.y = HIWORD (lParam);
4716 for (i = 0; i < NUM_ABOUT_LINKS; i++)
4717 {
4718 if (PtInRect(AboutLinks + i, pt))
4719 {
4720 SetCursor(LoadCursor(NULL, IDC_HAND));
4721 url = AboutURLs[i];
4722 return 0;
4723 }
4724 }
4725 SetCursor(LoadCursor(NULL, IDC_ARROW));
4726 url = NULL;
4727 return 0;
4728
4729 case WM_SETCURSOR:
4730 return 1;
4731
4732 case WM_LBUTTONUP:
4733 if (url != NULL)
4734 {
4735 SetCursor(LoadCursor(NULL, IDC_WAIT)); // will get changed on next mouse move
4736 ShellExecute (NULL, NULL, url, NULL, NULL, SW_SHOWNORMAL) ;
4737 }
4738 return (0) ;
4739
4740 case WM_COMMAND :
4741 if (HIWORD (wParam) != BN_CLICKED)
4742 return (false) ;
4743 for (button = 0 ; button < 3 ; button++)
4744 if (about_buttons [button] == (HWND) lParam)
4745 break ;
4746 if (button == 3)
4747 break ;
4748 switch (button)
4749 {
4750 case 0 :
4751 // if help file is missing or something, default to internal viewer
4752 if (stat (engineHelpPath, &st) == 0)
4753 {
4754 hh_aklink.pszKeywords = "POV-Ray License" ;
4755 if (HtmlHelp (main_window, engineHelpPath, HH_KEYWORD_LOOKUP, (DWORD_PTR) &hh_aklink))
4756 return (0) ;
4757 }
4758 DialogBoxParam (hInstance, MAKEINTRESOURCE (IDD_VIEW), main_window, (DLGPROC) PovLegalDialogProc, (LPARAM) main_window) ;
4759 break ;
4760
4761 case 1 :
4762 save_povlegal () ;
4763 break ;
4764
4765 case 2 :
4766 about_showing = false ;
4767 EnableWindow (main_window, TRUE) ;
4768 SetFocus (main_window) ;
4769 DestroyWindow (hwnd) ;
4770 break ;
4771 }
4772 return (0) ;
4773
4774 case WM_DRAWITEM :
4775 lpdis = (LPDRAWITEMSTRUCT) lParam ;
4776 for (button = 0 ; button < 3 ; button++)
4777 if (about_buttons [button] == lpdis->hwndItem)
4778 break ;
4779 if (button == 3)
4780 return (0) ;
4781 if ((lpdis->itemState & ODS_SELECTED) != 0)
4782 offset = 400;
4783 else if (GetWindowLongPtr(lpdis->hwndItem, GWLP_USERDATA) != 0)
4784 offset = 200;
4785 hdc = lpdis->hDC ;
4786 if (about_palette)
4787 SelectPalette (hdc, about_palette, true) ;
4788 hdcMemory = CreateCompatibleDC (hdc) ;
4789 oldBmp = (HBITMAP) SelectObject (hdcMemory, hBmpAbout) ;
4790 BitBlt (hdc, 0, 0, 165, 30, hdcMemory, offset, button * 30 + about_height, SRCCOPY) ;
4791 SelectObject (hdcMemory, oldBmp) ;
4792 DeleteDC (hdcMemory) ;
4793 return (1) ;
4794
4795 case WM_KEYDOWN :
4796 if (wParam == VK_RETURN || wParam == VK_ESCAPE || wParam == VK_SPACE)
4797 {
4798 EnableWindow (main_window, TRUE) ;
4799 SetFocus (main_window) ;
4800 DestroyWindow (hwnd) ;
4801 return (0) ;
4802 }
4803 return (0) ;
4804
4805 case WM_PAINT :
4806 hdc = BeginPaint (hwnd, &ps) ;
4807 if (about_palette)
4808 {
4809 SelectPalette (hdc, about_palette, false) ;
4810 RealizePalette (hdc) ;
4811 }
4812 hdcMemory = CreateCompatibleDC (hdc) ;
4813 oldBmp = (HBITMAP) SelectObject (hdcMemory, hBmpAbout) ;
4814 BitBlt (hdc, 0, 0, about_width, about_height, hdcMemory, 0, 0, SRCCOPY) ;
4815 SelectObject (hdcMemory, oldBmp) ;
4816 DeleteDC (hdcMemory) ;
4817 EndPaint (hwnd, &ps) ;
4818 return (0) ;
4819
4820 case WM_PALETTECHANGED :
4821 // make sure it wasn't us who changed the palette, otherwise we can get into an infinite loop.
4822 if ((HWND) wParam == hwnd)
4823 return (0) ;
4824 // FALL THROUGH to WM_QUERYNEWPALETTE
4825
4826 case WM_QUERYNEWPALETTE :
4827 if (about_palette)
4828 {
4829 hdc = GetDC (hwnd) ;
4830 oldPalette = SelectPalette (hdc, about_palette, false) ;
4831 f = (RealizePalette (hdc) != 0);
4832 SelectPalette (hdc, oldPalette, false) ;
4833 ReleaseDC (hwnd, hdc) ;
4834 if (f)
4835 PovInvalidateRect (hwnd, NULL, true) ;
4836 }
4837 return (0) ;
4838 }
4839 return (DefWindowProc (hwnd, message, wParam, lParam)) ;
4840 }
4841
PovAboutButtonWndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)4842 LRESULT CALLBACK PovAboutButtonWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4843 {
4844 TRACKMOUSEEVENT tme;
4845
4846 switch (message)
4847 {
4848 case WM_MOUSEMOVE:
4849 if (GetWindowLongPtr(hwnd, GWLP_USERDATA) != 0)
4850 break;
4851 tme.cbSize = sizeof(tme);
4852 tme.dwFlags = TME_LEAVE;
4853 tme.dwHoverTime = 0;
4854 tme.hwndTrack = hwnd;
4855 TrackMouseEvent(&tme);
4856 InvalidateRect (hwnd, NULL, false);
4857 SetWindowLongPtr(hwnd, GWLP_USERDATA, 1);
4858 break;
4859
4860 case WM_MOUSELEAVE:
4861 InvalidateRect (hwnd, NULL, false);
4862 SetWindowLongPtr(hwnd, GWLP_USERDATA, 0);
4863 break;
4864
4865 case WM_KEYDOWN:
4866 if (wParam != VK_ESCAPE)
4867 break;
4868 EnableWindow (main_window, TRUE) ;
4869 SetFocus (main_window) ;
4870 DestroyWindow (about_window) ;
4871 return (0) ;
4872 }
4873 return (CallWindowProc (about_button_wndproc, hwnd, message, wParam, lParam)) ;
4874 }
4875
ShowAboutBox(void)4876 void ShowAboutBox (void)
4877 {
4878 int oldMode ;
4879 MSG msg ;
4880 HDC hdcMemory ;
4881 char *s = POV_RAY_VERSION COMPILER_VER SSE2_INCLUDED "." PVENGINE_VER ;
4882 SIZE size ;
4883 HFONT oldFont ;
4884 BITMAP bm ;
4885 HBITMAP oldBmp ;
4886 COLORREF oldColour ;
4887
4888 if ((hBmpAbout = NonBogusLoadBitmapAndPalette (hInstance, MAKEINTRESOURCE (BMP_ABOUT))) != NULL)
4889 {
4890 GetObject (hBmpAbout, sizeof (BITMAP), (LPSTR) &bm) ;
4891 about_width = bm.bmWidth ;
4892 about_height = bm.bmHeight - 180 ;
4893 about_palette = hPalBitmap ;
4894
4895 if (about_font == NULL)
4896 create_about_font () ;
4897
4898 hdcMemory = CreateCompatibleDC (NULL) ;
4899 oldFont = (HFONT) SelectObject (hdcMemory, about_font) ;
4900 oldMode = SetBkMode (hdcMemory, TRANSPARENT) ;
4901 oldColour = SetTextColor (hdcMemory, RGB (0x96, 0xD3, 0xFF)) ;
4902 oldBmp = (HBITMAP) SelectObject (hdcMemory, hBmpAbout) ;
4903 GetTextExtentPoint (hdcMemory, s, (int) strlen (s), &size) ;
4904 ExtTextOut (hdcMemory, 387, 14, 0, NULL, s, (int) strlen (s), NULL) ;
4905 SetTextColor (hdcMemory, oldColour) ;
4906 SetBkMode (hdcMemory, oldMode) ;
4907 SelectObject (hdcMemory, oldFont) ;
4908 SelectObject (hdcMemory, oldBmp) ;
4909 DeleteDC (hdcMemory) ;
4910
4911 about_window = CreateWindowEx (0,//WS_EX_TOOLWINDOW,
4912 PovAboutWinClass,
4913 "POV-Ray",
4914 WS_POPUP,
4915 (screen_width - about_width) / 2,
4916 (screen_height - about_height) / 2,
4917 about_width,
4918 about_height,
4919 main_window,
4920 NULL,
4921 hInstance,
4922 NULL) ;
4923 for (int i = 0; i < 3; i++)
4924 {
4925 about_buttons[i] = CreateWindow ("BUTTON", "", WS_VISIBLE | WS_CHILD | BS_OWNERDRAW, i * 184 + 27, 451, 165, 30, about_window, NULL, hInstance, NULL) ;
4926 about_button_wndproc = (WNDPROC) (ULONG_PTR) SetWindowLongPtr (about_buttons[i], GWLP_WNDPROC, (ULONG_PTR) PovAboutButtonWndProc) ;
4927 }
4928 CenterWindowRelative (main_window, about_window, false, true) ;
4929 ShowWindow (about_window, SW_SHOWNORMAL) ;
4930 SetFocus (about_window) ;
4931 EnableWindow (main_window, FALSE) ;
4932 while (about_showing && GetMessage (&msg, NULL, 0, 0) != 0 && quit == 0)
4933 {
4934 if (!TranslateAccelerator (main_window, hAccelerators, &msg))
4935 {
4936 TranslateMessage (&msg) ;
4937 DispatchMessage (&msg) ;
4938 }
4939 }
4940 }
4941 }
4942
4943 /**************************************************************************************/
4944 /* END OF WINDOW PROCEDURES */
4945 /**************************************************************************************/
4946
register_classes(void)4947 int register_classes (void)
4948 {
4949 WNDCLASSEX wc ;
4950
4951 // the parameter to RegisterClass is considered CONST, so we
4952 // can assume that the structure is not changed by the calls.
4953 wc.cbSize = sizeof (wc) ;
4954 wc.hIconSm = NULL ;
4955 wc.cbClsExtra = 0 ;
4956 wc.cbWndExtra = 0 ;
4957 wc.hInstance = hInstance ;
4958 wc.lpszMenuName = NULL ;
4959 wc.hbrBackground = NULL ;
4960
4961 // Register the main window class.
4962 wc.style = CS_BYTEALIGNCLIENT ;
4963 wc.lpfnWndProc = PovMainWndProc ;
4964 wc.hIcon = ourIcon ;
4965 wc.hCursor = LoadCursor (NULL, IDC_ARROW) ;
4966 wc.lpszClassName = PovMainWinClass ;
4967 if (RegisterClassEx (&wc) == false)
4968 return (false) ;
4969
4970 // Register the message window class.
4971 wc.style = CS_BYTEALIGNCLIENT ;
4972 wc.lpfnWndProc = PovMessageWndProc ;
4973 wc.hIcon = NULL ;
4974 wc.hCursor = LoadCursor (NULL, IDC_ARROW) ;
4975 wc.lpszClassName = PovMessageWinClass ;
4976 if (RegisterClassEx (&wc) == false)
4977 return (false) ;
4978
4979 // Register the about window class.
4980 wc.style = CS_BYTEALIGNCLIENT ;
4981 wc.lpfnWndProc = PovAboutWndProc ;
4982 wc.hIcon = ourIcon ;
4983 wc.hCursor = LoadCursor (NULL, IDC_ARROW) ;
4984 wc.lpszClassName = PovAboutWinClass ;
4985 if (RegisterClassEx (&wc) == false)
4986 return (false) ;
4987
4988 // Register the render window classes
4989 wc.style = CS_BYTEALIGNCLIENT ;
4990 wc.lpfnWndProc = WinLegacyDisplay::StaticWindowProc ;
4991 wc.hIcon = renderIcon ;
4992 wc.hCursor = LoadCursor (NULL, IDC_CROSS) ;
4993 wc.hbrBackground = NULL ;
4994 wc.lpszClassName = PovLegacyRenderWinClass ;
4995 wc.cbWndExtra = 8 ;
4996 if (RegisterClassEx (&wc) == false)
4997 return (false) ;
4998
4999 return (true) ;
5000 }
5001
cleanup_all(void)5002 void cleanup_all (void)
5003 {
5004 // TODO: nuke any render threads still running
5005 ExternalCleanupAll () ;
5006 EditUnload () ;
5007 if (use_taskbar)
5008 TaskBarDeleteIcon (main_window, 0) ;
5009 clear_messages (false) ;
5010 clear_dir_restrictions () ;
5011 DeleteCriticalSection (&critical_section) ;
5012 display_cleanup (true) ;
5013 if (hBmpBackground != NULL)
5014 DeleteObject (hBmpBackground) ;
5015 if (hBmpRendering != NULL)
5016 DeleteObject (hBmpRendering) ;
5017 if (hBmpIcon != NULL)
5018 DeleteObject (hBmpIcon) ;
5019 if (hMenuBar)
5020 DestroyMenu (hMenuBar) ;
5021 if (hMainMenu)
5022 DestroyMenu (hMainMenu) ;
5023 if (hPopupMenus)
5024 DestroyMenu (hPopupMenus) ;
5025 if (hPalApp)
5026 DeleteObject (hPalApp) ;
5027 if (message_font)
5028 DeleteObject (message_font) ;
5029 if (about_font)
5030 DeleteObject (about_font) ;
5031 if (tab_font)
5032 DeleteObject (tab_font) ;
5033 if (ourIcon)
5034 DestroyIcon (ourIcon) ;
5035 if (renderIcon)
5036 DestroyIcon (renderIcon) ;
5037
5038 UnregisterClass (PovLegacyRenderWinClass, hInstance) ;
5039 UnregisterClass (PovMessageWinClass, hInstance) ;
5040 UnregisterClass (PovMainWinClass, hInstance) ;
5041 }
5042
5043 #ifdef _MSC_VER
LZTimerOn(void)5044 void LZTimerOn (void)
5045 {
5046 if (!QueryPerformanceCounter ((LARGE_INTEGER *) &PerformanceCounter1))
5047 PerformanceCounter1 = 0 ;
5048 }
5049
LZTimerOff(void)5050 void LZTimerOff (void)
5051 {
5052 if (!QueryPerformanceCounter ((LARGE_INTEGER *) &PerformanceCounter2))
5053 PerformanceCounter2 = 0 ;
5054 }
5055
LZTimerCount(void)5056 ulong LZTimerCount (void)
5057 {
5058 if (PerformanceCounter1 == 0 || PerformanceCounter2 < PerformanceCounter1)
5059 return (0) ;
5060 return ((ulong) ((PerformanceCounter2 - PerformanceCounter1) / PerformanceScale)) ;
5061 }
5062
LZTimerRawCount(void)5063 __int64 LZTimerRawCount (void)
5064 {
5065 if (PerformanceCounter1 == 0 || PerformanceCounter2 < PerformanceCounter1)
5066 return (0) ;
5067 return (PerformanceCounter2 - PerformanceCounter1) ;
5068 }
5069 #endif // #ifdef _MSC_VER
5070
5071 }
5072
newhandler(void)5073 static void __cdecl newhandler (void)
5074 {
5075 throw std::bad_alloc () ;
5076 }
5077
5078 using namespace povwin ;
5079
GenerateDumpMeta(bool brief)5080 void GenerateDumpMeta(bool brief)
5081 {
5082 char str[128];
5083 char *s = DumpMeta;
5084 char *InstalledOn ;
5085 HDC hdc ;
5086 HKEY key ;
5087 DWORD len;
5088 DWORD header = 0 ;
5089 DWORD n ;
5090 FILETIME file_time ;
5091 SYSTEMTIME system_time ;
5092 SYSTEM_INFO sysinfo ;
5093 OSVERSIONINFO version_info ;
5094 MEMORYSTATUSEX mem_status ;
5095
5096 GetNativeSystemInfo(&sysinfo) ;
5097 if (!brief)
5098 {
5099 if ((InstalledOn = GetInstallTime()) == NULL)
5100 {
5101 GetSystemTime (&system_time) ;
5102 if (SystemTimeToFileTime (&system_time, &file_time))
5103 reg_printf (true, "Software\\POV-Ray", INSTALLTIMEKEY, "%I64u", ((__int64) file_time.dwHighDateTime << 32) | file_time.dwLowDateTime) ;
5104 if ((InstalledOn = GetInstallTime ()) == NULL)
5105 InstalledOn = "Unknown" ;
5106 }
5107 s += sprintf(s, "installdate=%s\n", InstalledOn) ;
5108 }
5109 s += sprintf(s, "cpuarchitecture=%u\n", (DWORD) sysinfo.wProcessorArchitecture) ;
5110 s += sprintf(s, "numberofcpus=%u\n", sysinfo.dwNumberOfProcessors) ;
5111 s += sprintf(s, "processortype=%u\n", sysinfo.dwProcessorType) ;
5112 s += sprintf(s, "processorlevel=%u\n", (DWORD) sysinfo.wProcessorLevel) ;
5113 s += sprintf(s, "processorrevision=%u\n", (DWORD) sysinfo.wProcessorRevision) ;
5114
5115 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, "HARDWARE\\Description\\System\\CentralProcessor\\0", 0, KEY_READ, &key) == ERROR_SUCCESS)
5116 {
5117 len = sizeof (n) ;
5118 if (RegQueryValueEx (key, "~MHZ", 0, NULL, (BYTE *) &n, &len) == ERROR_SUCCESS)
5119 s += sprintf(s, "cpufrequency=%u\n", n) ;
5120
5121 len = sizeof (n) ;
5122 if (RegQueryValueEx (key, "FeatureSet", 0, NULL, (BYTE *) &n, &len) == ERROR_SUCCESS)
5123 s += sprintf(s, "cpufeatureset=%u\n", n) ;
5124
5125 len = sizeof (str) ;
5126 if (RegQueryValueEx (key, "ProcessorNameString", 0, NULL, (BYTE *) str, &len) == ERROR_SUCCESS)
5127 s += sprintf(s, "cpuname=%s\n", str) ;
5128
5129 len = sizeof (str) ;
5130 if (RegQueryValueEx (key, "Identifier", 0, NULL, (BYTE *) str, &len) == ERROR_SUCCESS)
5131 s += sprintf(s, "cpuidentifier=%s\n", str) ;
5132
5133 len = sizeof (str) ;
5134 if (RegQueryValueEx (key, "VendorIdentifier", 0, NULL, (BYTE *) str, &len) == ERROR_SUCCESS)
5135 s += sprintf(s, "cpuvendoridentifier=%s\n", str) ;
5136
5137 RegCloseKey (key) ;
5138 }
5139
5140 version_info.dwOSVersionInfoSize = sizeof (OSVERSIONINFO) ;
5141 GetVersionEx (&version_info) ;
5142 s += sprintf(s, "osversion=%u.%u\n", version_info.dwMajorVersion, version_info.dwMinorVersion) ;
5143 s += sprintf(s, "osbuild=%u\n", version_info.dwBuildNumber) ;
5144 s += sprintf(s, "csdversion=%s\n", version_info.szCSDVersion) ;
5145
5146 if (!brief)
5147 {
5148 hdc = GetDC (NULL) ;
5149 s += sprintf(s, "bitsperpixel=%u\n", GetDeviceCaps (hdc, BITSPIXEL)) ;
5150 s += sprintf(s, "horzres=%u\n", GetDeviceCaps (hdc, HORZRES)) ;
5151 s += sprintf(s, "vertres=%u\n", GetDeviceCaps (hdc, VERTRES)) ;
5152 ReleaseDC (NULL, hdc) ;
5153 }
5154
5155 mem_status.dwLength = sizeof (MEMORYSTATUSEX) ;
5156 GlobalMemoryStatusEx(&mem_status) ;
5157 s += sprintf(s, "physicalmemory=%I64u\n", mem_status.ullTotalPhys) ;
5158 }
5159
WriteDumpMeta(struct _EXCEPTION_POINTERS * ExceptionInfo,const char * filename)5160 bool WriteDumpMeta(struct _EXCEPTION_POINTERS *ExceptionInfo, const char *filename)
5161 {
5162 FILE *f;
5163 PCONTEXT c = ExceptionInfo->ContextRecord ;
5164 static char fn[_MAX_PATH];
5165
5166 strcpy(fn, filename);
5167 strcat(fn, ".metadata");
5168
5169 if ((f = fopen(fn, "wt")) == NULL)
5170 return false;
5171 fwrite(DumpMeta, strlen(DumpMeta), 1, f);
5172 fprintf(f, "faulttype=%u\n", ExceptionInfo->ExceptionRecord->ExceptionCode);
5173 #ifdef _WIN64
5174 fprintf(f, "faultaddress=%I64u\n", ExceptionInfo->ContextRecord->Rip);
5175 fprintf(f, "faultplatform=win64\n");
5176 #else
5177 fprintf(f, "faultaddress=%u\n", ExceptionInfo->ContextRecord->Eip);
5178 fprintf(f, "faultplatform=win32\n");
5179 #endif
5180 fprintf(f, "povversion=%s\n", POV_RAY_VERSION) ;
5181 fprintf(f, "compilerversion=%s\n", COMPILER_VER) ;
5182 fprintf(f, "platformversion=%s\n", PVENGINE_VER) ;
5183 fprintf(f, "remotesession=%u\n", GetSystemMetrics(SM_REMOTESESSION)) ;
5184 fclose(f);
5185 return true;
5186 }
5187
5188 // TODO: re-write this!!!
WriteDump(struct _EXCEPTION_POINTERS * pExceptionInfo,bool full,long timestamp)5189 char *WriteDump(struct _EXCEPTION_POINTERS *pExceptionInfo, bool full, long timestamp)
5190 {
5191 // firstly see if dbghelp.dll is around and has the function we need
5192 // look next to the EXE first, as the one in System32 might be old
5193 // (e.g. Windows 2000)
5194 HMODULE hDll = NULL;
5195 static char szDbgHelpPath[_MAX_PATH];
5196
5197 if (GetModuleFileName(NULL, szDbgHelpPath, _MAX_PATH ))
5198 {
5199 char *pSlash = findLastPathSeparator( szDbgHelpPath );
5200 if (pSlash)
5201 {
5202 strcpy( pSlash+1, "DBGHELP.DLL" );
5203 hDll = ::LoadLibrary( szDbgHelpPath );
5204 }
5205 }
5206
5207 if (hDll==NULL)
5208 {
5209 // load any version we can
5210 hDll = ::LoadLibrary( "DBGHELP.DLL" );
5211 }
5212
5213 LPCTSTR szResult = NULL;
5214
5215 if (hDll)
5216 {
5217 MINIDUMPWRITEDUMP pDump = (MINIDUMPWRITEDUMP)::GetProcAddress( hDll, "MiniDumpWriteDump" );
5218 if (pDump)
5219 {
5220 char szScratch [_MAX_PATH];
5221 static char szDumpPath[_MAX_PATH];
5222
5223 if (full)
5224 sprintf(szScratch, "POV-Ray-" POV_RAY_VERSION COMPILER_VER SSE2_INCLUDED "." PVENGINE_VER "-%08X.dmp", timestamp);
5225 else
5226 sprintf(szScratch, "POV-Ray-" POV_RAY_VERSION COMPILER_VER SSE2_INCLUDED "." PVENGINE_VER "-%08X.minidump", timestamp);
5227
5228 // work out a good place for the dump file
5229 if (!GetTempPath( _MAX_PATH - 64, szDumpPath))
5230 _tcscpy( szDumpPath, "c:\\" );
5231
5232 _tcscat( szDumpPath, szScratch );
5233
5234 // create the file
5235 HANDLE hFile = ::CreateFile( szDumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
5236
5237 if (hFile!=INVALID_HANDLE_VALUE)
5238 {
5239 _MINIDUMP_EXCEPTION_INFORMATION ExInfo;
5240
5241 ExInfo.ThreadId = ::GetCurrentThreadId();
5242 ExInfo.ExceptionPointers = pExceptionInfo;
5243 ExInfo.ClientPointers = NULL;
5244
5245 // write the dump
5246 BOOL bOK = pDump(GetCurrentProcess(),
5247 GetCurrentProcessId(),
5248 hFile,
5249 full ? MiniDumpWithFullMemory :
5250 (MINIDUMP_TYPE)(MiniDumpWithDataSegs|MiniDumpWithHandleData|MiniDumpWithIndirectlyReferencedMemory), &ExInfo, NULL, NULL );
5251 ::CloseHandle(hFile);
5252 if (bOK)
5253 {
5254 if (!WriteDumpMeta(pExceptionInfo, szDumpPath))
5255 {
5256 MessageBox (main_window, "Failed to save dump metadata file", "POV-Ray for Windows", MB_OK | MB_ICONEXCLAMATION);
5257 return NULL;
5258 }
5259 return szDumpPath;
5260 }
5261 sprintf( szScratch, "Failed to save dump file to '%s' (error %d)", szDumpPath, GetLastError() );
5262 MessageBox (main_window, szScratch, "POV-Ray for Windows", MB_OK | MB_ICONEXCLAMATION);
5263 return NULL;
5264 }
5265 sprintf( szScratch, "Failed to create dump file '%s' (error %d)", szDumpPath, GetLastError() );
5266 MessageBox (main_window, szScratch, "POV-Ray for Windows", MB_OK | MB_ICONEXCLAMATION);
5267 return NULL;
5268 }
5269 MessageBox (main_window, "Sorry, DBGHELP.DLL is too old - cannot create dump.", "POV-Ray for Windows", MB_OK | MB_ICONEXCLAMATION);
5270 return NULL;
5271 }
5272 MessageBox (main_window, "Sorry, we can't locate DBGHELP.DLL - cannot create dump.", "POV-Ray for Windows", MB_OK | MB_ICONEXCLAMATION);
5273 return NULL;
5274 }
5275
5276 #ifdef BUILD_SSE2
NoSSE2(void)5277 void NoSSE2 (void)
5278 {
5279 MessageBox (NULL,
5280 "This build of POV-Ray requires that your processor provides SSE2 support.\n"
5281 "Please use the standard non-SSE2 version of POV-Ray on this computer.",
5282 "POV-Ray for Windows",
5283 MB_ICONSTOP | MB_OK) ;
5284 exit (-1) ;
5285 }
5286
TestSSE2(void)5287 inline int TestSSE2 (void)
5288 {
5289 __try
5290 {
5291 __asm { movapd xmm0,xmm1 }
5292 }
5293 __except(NoSSE2(),1)
5294 {
5295 }
5296 return (0) ;
5297 }
5298 #endif
5299
InvalidParameterHandler(const wchar_t * expression,const wchar_t * function,const wchar_t * file,unsigned int line,uintptr_t pReserved)5300 void InvalidParameterHandler(const wchar_t* expression, const wchar_t* function, const wchar_t* file, unsigned int line, uintptr_t pReserved)
5301 {
5302 throw POV_EXCEPTION(kParamErr, "Run-Time Library Invalid Parameter Handler invoked");
5303 }
5304
WinMain(HINSTANCE hInst,HINSTANCE hPrev,LPSTR szCmdLine,int sw)5305 int PASCAL WinMain (HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw)
5306 {
5307 #ifdef BUILD_SSE2
5308 TestSSE2 () ;
5309 #endif
5310
5311 int show_state ;
5312 int i ;
5313 int id = 0 ;
5314 int w, h ;
5315 char str [_MAX_PATH * 2] ;
5316 char *s = szCmdLine ;
5317 bool exit_loop = false ;
5318 bool have_cpu_info = false;
5319 unsigned n ;
5320 MSG msg ;
5321 HDC hDC ;
5322 HDIB hDIB ;
5323 RECT rect ;
5324 HWND hwnd ;
5325 DWORD help_cookie ;
5326 DWORD threadId = 0 ;
5327 DWORD threadParam = 0 ;
5328 BITMAP bm ;
5329 HBITMAP hBMP ;
5330 struct stat statbuf ;
5331 SYSTEM_INFO sysinfo ;
5332 WINDOWPLACEMENT placement ;
5333
5334 // REMINDER: don't try to write to the message pane until initialise_message_display() has been called.
5335
5336 _set_invalid_parameter_handler(InvalidParameterHandler);
5337
5338 #ifdef _DEBUG
5339 _unlink ("c:\\temp\\povdebug.txt") ;
5340 _unlink ("c:\\temp\\povmem.txt") ;
5341 #endif
5342
5343 GenerateDumpMeta(false);
5344 std::set_new_handler(newhandler) ;
5345 SetUnhandledExceptionFilter(ExceptionHandler);
5346
5347 // need this now to set virtual_screen_width etc., in case we display a dialog
5348 // before the main setup (we call it again once we've read the INI file).
5349 detect_graphics_config () ;
5350
5351 try
5352 {
5353 CreateFrontend();
5354 }
5355 catch (pov_base::Exception& e)
5356 {
5357 sprintf (str, "Failed to initialize frontend: %s", e.what()) ;
5358 MessageBox (NULL, str, "POV-Ray Critical Error", MB_ICONSTOP) ;
5359 return (1) ;
5360 }
5361
5362 hInstance = hInst ;
5363 hMainThread = GetCurrentThread () ;
5364
5365 GetSystemInfo (&sysinfo) ;
5366 ThreadCount = sysinfo.dwNumberOfProcessors ;
5367 NumberOfCPUs = sysinfo.dwNumberOfProcessors ;
5368
5369 if (GetCPUCount(&NumLogicalCPUs, &NumCPUCores, &NumPhysicalCPUs) && NumLogicalCPUs > 1)
5370 {
5371 have_cpu_info = true;
5372 ThreadCount = NumLogicalCPUs ;
5373 NumberOfCPUs = NumCPUCores ;
5374 }
5375
5376 while (*s == ' ' || *s == '\t')
5377 s++ ;
5378 if (_stricmp (s, "/install") == 0 || _strnicmp (s, "/install ", 9) == 0 || _stricmp (s, "/qinstall") == 0 || _strnicmp (s, "/qinstall ", 10) == 0)
5379 {
5380 bool quiet = s [1] == 'q' || s [1] == 'Q' ;
5381 while (*s && *s != ' ')
5382 s++ ;
5383 argv[1] = argv[2] = NULL;
5384 parse_commandline(s);
5385 return (InstallSettings (argv[1], argv[2], quiet)) ;
5386 }
5387
5388 getHome () ;
5389 if (BinariesPath [0] == '\0')
5390 {
5391 inferHome () ;
5392 if (BinariesPath [0] == '\0')
5393 {
5394 MessageBox (NULL,
5395 "ERROR : Cannot find Home entry in registry (and cannot infer it).\n\n"
5396 "This entry should have been set by the installation program.\n\n"
5397 "POV-Ray can usually infer the installation path but that requires a\n"
5398 "standard layout of directories, which also seems to be absent.\n\n"
5399 "If you did not install using the correct installation procedure, please\n"
5400 "do this before running POV-Ray for Windows. You can also try running\n"
5401 "with the '/INSTALL' or '/INSTALL <bindir> [<docdir>]' option.",
5402 "Critical Error",
5403 MB_ICONSTOP) ;
5404 return (1) ;
5405 }
5406 }
5407 appendPathSeparator(BinariesPath) ;
5408 if (DocumentsPath[0] == '\0')
5409 {
5410 if (SHGetFolderPath (NULL, CSIDL_MYDOCUMENTS, NULL, SHGFP_TYPE_CURRENT, DocumentsPath) != S_OK)
5411 {
5412 MessageBox (NULL,
5413 "ERROR : Cannot find DocPath entry in registry (and cannot infer it).\n\n"
5414 "This entry should have been set by the installation program.\n\n"
5415 "POV-Ray can usually infer the installation path but that requires a\n"
5416 "standard layout of directories, which also seems to be absent.\n\n"
5417 "If you did not install using the correct installation procedure, please\n"
5418 "do this before running POV-Ray for Windows. You can also try running\n"
5419 "with the '/INSTALL' or '/INSTALL <bindir> <docdir>' option.",
5420 "Critical Error",
5421 MB_ICONSTOP) ;
5422 }
5423 strcat(DocumentsPath, "\\" REGKEY);
5424 if (!dirExists(DocumentsPath))
5425 CreateDirectory(DocumentsPath, NULL);
5426 strcat(DocumentsPath, "\\" REGVERKEY);
5427 if (!dirExists(DocumentsPath))
5428 CreateDirectory(DocumentsPath, NULL);
5429 }
5430 appendPathSeparator(DocumentsPath) ;
5431 sprintf(str, "%sini", DocumentsPath);
5432 if (!dirExists(str))
5433 CreateDirectory(str, NULL);
5434 sprintf(ToolIniFileName, "%sini\\pvtools.ini", DocumentsPath);
5435 sprintf(EngineIniFileName, "%sini\\pvengine.ini", DocumentsPath);
5436
5437 if (checkEditKey37() == false && checkEditKey36() == true)
5438 copy36EditSettings();
5439
5440 if (checkRegKey () == false || FreshInstall == true)
5441 if (!CloneOptions())
5442 MessageBox (NULL, "ERROR : Could not clone options - POV-Ray may not work correctly for this user.", "Critical Error", MB_ICONERROR) ;
5443
5444 #ifdef POVRAY_IS_BETA
5445 if (FreshInstall)
5446 {
5447 // on installing a new beta, we always turn on check new version now that we no longer
5448 // implement a short timeout. the user may switch it off if they like; we will not perform
5449 // an automatic version check in this session since FreshInstall is set, in order to give
5450 // them a chance to do it.
5451 check_new_version = true;
5452 PutHKCU("General", "CheckNewVersion", true);
5453 }
5454 #endif
5455
5456 #ifndef MAP_INI_TO_REGISTRY
5457 if (!fileExists(EngineIniFileName))
5458 {
5459 // no INI file: see if we can copy the 3.6 INI options, should they exist
5460 if (debugging)
5461 debug_output("no pvengine.ini: seeing if there is a v3.6 ini\n") ;
5462
5463 string str(get36Home());
5464 if (str.empty() == false)
5465 {
5466 string oldINIpath = str + "ini\\pvengine.ini";
5467 if (fileExists(oldINIpath.c_str()))
5468 {
5469 if (debugging)
5470 debug_output("cloning INI file %s to %s\n", oldINIpath.c_str(), EngineIniFileName) ;
5471 cloneOldIni(str, DocumentsPath);
5472 }
5473 else
5474 {
5475 if (debugging)
5476 debug_output("creating default INI file %s\n", EngineIniFileName) ;
5477 cloneOldIni("", DocumentsPath);
5478 }
5479 }
5480 else
5481 {
5482 if (debugging)
5483 debug_output("creating default INI file %s\n", EngineIniFileName) ;
5484 cloneOldIni("", DocumentsPath);
5485 }
5486 }
5487 #endif
5488
5489 if (homeInferred)
5490 {
5491 if (_stricmp (LastInferredHome, BinariesPath) != 0)
5492 {
5493 sprintf (str, "POV-Ray for Windows did not find the expected registry entries present.\n"
5494 "This typically means that it has not been installed via the installation program.\n"
5495 "You can correct this by running with the '/INSTALL' or '/INSTALL <installdir>' option.\n\n"
5496 "POV-Ray has inferred the installation path to be the following:\n\n"
5497 "\t%s\n\n"
5498 "This message will be displayed each time the inferred path changes.",
5499 BinariesPath) ;
5500 MessageBox (NULL, str, "Warning", MB_ICONINFORMATION) ;
5501 }
5502 reg_printf (true, "Software\\" REGKEY "\\" REGVERKEY "\\Windows", "LastInferredHome", "%s", BinariesPath) ;
5503 }
5504
5505 sprintf(ToolIniFileName, "%sini\\pvtools.ini", DocumentsPath);
5506 sprintf (DefaultRenderIniFileName, "%sini\\povray.ini", DocumentsPath) ;
5507 GetModuleFileName (hInst, str, sizeof (str) - 1) ;
5508 splitpath (str, modulePath, NULL) ;
5509 validatePath (modulePath) ;
5510
5511 sprintf (engineHelpPath, "%shelp\\povray37.chm", BinariesPath) ;
5512 HtmlHelp (NULL, NULL, HH_INITIALIZE, (DWORD_PTR) &help_cookie) ;
5513 memset (&hh_aklink, 0, sizeof (hh_aklink)) ;
5514 hh_aklink.cbStruct = sizeof (hh_aklink) ;
5515 hh_aklink.fIndexOnFail = true ;
5516 hh_aklink.pszWindow = "POV-Ray Help" ;
5517
5518 SHGetFolderPath (NULL, CSIDL_FONTS, NULL, SHGFP_TYPE_CURRENT, FontPath) ;
5519
5520 one_instance = GetHKCU("General", "OneInstance", 1) != 0 ;
5521 if ((hwnd = FindWindow (PovMainWinClass, NULL)) != NULL)
5522 {
5523 if (one_instance)
5524 {
5525 if (IsIconic (hwnd))
5526 ShowWindow (hwnd, SW_RESTORE) ;
5527 SetForegroundWindow (hwnd) ;
5528 FeatureNotify ("OneInstanceSet",
5529 "POV-Ray - 'Keep Single Instance' Feature",
5530 "You have started POV-Ray for Windows while another copy is running, "
5531 "and the 'Keep Single Instance' option is turned on (see Options menu). "
5532 "In this case the other copy is activated rather than starting a new "
5533 "instance of the program.\n\nClick &Help for information on this feature.",
5534 "Keep Single Instance",
5535 false) ;
5536
5537 // special case: there's a chance we're being called as a result of a windows file association
5538 // default, which allows users to associate POV-Ray with arbitrary files. in this case, no
5539 // /EDIT or /RENDER verb will be present; just the filename. what we do here is see if the
5540 // passed string is a real file by calling fileExists(). if it is, then we assume /EDIT is
5541 // desired.
5542 n = strlen(szCmdLine);
5543 if (n < _MAX_PATH && n > 2 && szCmdLine[0] == '"' && szCmdLine[n - 1] == '"')
5544 {
5545 memcpy(str, szCmdLine + 1, n - 2);
5546 str[n - 2] = '\0';
5547 if (fileExists(str))
5548 {
5549 FeatureNotify ("EditByDefault",
5550 "POV-Ray - Filename passed on command-line",
5551 "Quoted filenames which are the sole command-line parameter are now "
5552 "opened in the editor by default. If you wish to render them instead "
5553 "please pass the /RENDER switch, provide more than one parameter, or "
5554 "use single quotes around the path.\n\n"
5555 "Click &Help for more information.",
5556 "associations", false) ;
5557 add_edit_file(str);
5558 szCmdLine = "";
5559 }
5560 }
5561
5562 SetForegroundWindow (hwnd) ;
5563 if ((s = preparse_instance_commandline (szCmdLine)) != NULL)
5564 {
5565 parse_commandline(s);
5566 if (argc > 1)
5567 {
5568 PovMessageBox ("Only /EDIT and /RENDER may be passed to previous instance", "Commandline processing error") ;
5569 return (1) ;
5570 }
5571 COPYDATASTRUCT cd ;
5572 cd.dwData = EDIT_FILE ;
5573 for (i = 0 ; i < EditFileCount ; i++)
5574 {
5575 s = EditFiles [i] ;
5576 if ((isalpha (s [0]) && s [1] == ':') || (isPathSeparator(s [0]) && isPathSeparator(s [1])))
5577 {
5578 cd.cbData = (int) strlen (s) + 1 ;
5579 cd.lpData = s ;
5580 }
5581 else
5582 {
5583 GetCurrentDirectory (sizeof (str), str) ;
5584 if (!isPathSeparator(s [0]))
5585 {
5586 strcat (str, "\\") ;
5587 strcat (str, s) ;
5588 }
5589 else
5590 strcpy (str + 2, s) ;
5591 cd.cbData = (int) strlen (str) + 1 ;
5592 cd.lpData = str ;
5593 }
5594 SendMessage (hwnd, WM_COPYDATA, NULL, (LPARAM) &cd) ;
5595 free (EditFiles [i]) ;
5596 EditFiles [i] = NULL ;
5597 }
5598 EditFileCount = 0 ;
5599 if (render_requested)
5600 {
5601 cd.dwData = RENDER_FILE ;
5602 s = requested_render_file ;
5603 if ((isalpha (s [0]) && s [1] == ':') || (isPathSeparator(s [0]) && isPathSeparator(s [1])))
5604 {
5605 cd.cbData = (int) strlen (s) + 1 ;
5606 cd.lpData = s ;
5607 }
5608 else
5609 {
5610 GetCurrentDirectory (sizeof (str), str) ;
5611 if (!isPathSeparator(s [0]))
5612 {
5613 strcat (str, "\\") ;
5614 strcat (str, s) ;
5615 }
5616 else
5617 strcpy (str + 2, s) ;
5618 cd.cbData = (int) strlen (str) + 1 ;
5619 cd.lpData = str ;
5620 }
5621 SendMessage (hwnd, WM_COPYDATA, NULL, (LPARAM) &cd) ;
5622 }
5623 SetForegroundWindow (hwnd) ;
5624 }
5625 else
5626 return (1) ;
5627 return (0) ;
5628 }
5629 else
5630 {
5631 // one_instance isn't set. we should continue as per normal.
5632 // however see if we need to notify the user about this.
5633 FeatureNotify ("OneInstanceUnset",
5634 "POV-Ray - 'Keep Single Instance' Feature",
5635 "You have started POV-Ray for Windows while another copy is running, "
5636 "and the 'Keep Single Instance' option is turned off (see Options menu). "
5637 "In this case a new instance of the program is started rather than "
5638 "activating the existing instance of the program.\n\nClick &Help for more "
5639 "information on this feature.",
5640 "Keep Single Instance",
5641 false) ;
5642 }
5643 }
5644
5645 if (_strnicmp (szCmdLine, "/DEBUG", 6) == 0)
5646 {
5647 debugging = true ;
5648 debug_output(NULL) ;
5649 }
5650
5651 SetThreadPriority (hMainThread, THREAD_PRIORITY_ABOVE_NORMAL) ;
5652 version_info.dwOSVersionInfoSize = sizeof (OSVERSIONINFO) ;
5653 GetVersionEx (&version_info) ;
5654 use_editors = editors_enabled ;
5655
5656 IsW98 = HaveWin98OrLater () ;
5657 IsWNT = HaveNT4OrLater () ;
5658 IsW2k = HaveWin2kOrLater () ;
5659 IsWXP = HaveWinXPOrLater () ;
5660 IsVista = HaveVistaOrLater () ;
5661
5662 // yes, we actually used to support the windows 3.1 UI ...
5663 IsW95UserInterface = true ;
5664
5665 ourIcon = LoadIcon (hInstance, MAKEINTRESOURCE (IsWXP ? IDI_PVENGINE_XP : IDI_PVENGINE)) ;
5666 renderIcon = LoadIcon (hInstance, MAKEINTRESOURCE (IsWXP ? IDI_RENDERWINDOW_XP : IDI_RENDERWINDOW)) ;
5667
5668 if (hPrev == NULL)
5669 if (register_classes () == false)
5670 MessageBox (NULL, "ERROR : Could not register classes", "Error", MB_ICONSTOP) ;
5671
5672 IsComCtl5 = GetDllVersion (TEXT ("comctl32.dll")) >= MAKELONG (5,0) ;
5673 IsComCtl6 = GetDllVersion (TEXT ("comctl32.dll")) >= MAKELONG (6,0) ;
5674
5675 // need to init menus before we read INI settings
5676 init_menus () ;
5677
5678 // need to do this before we detect the graphics config
5679 read_INI_settings () ;
5680
5681 detect_graphics_config () ;
5682 clear_system_palette () ;
5683 hPalApp = WinLegacyDisplay::CreatePalette (NULL, 0, render_bitmap_depth != 24) ;
5684
5685 if (!QueryPerformanceFrequency ((LARGE_INTEGER *) &PerformanceFrequency))
5686 PerformanceFrequency = 0 ;
5687 if (PerformanceFrequency > 1999999)
5688 PerformanceScale = PerformanceFrequency / 1000000 ;
5689
5690 // 'IsW95UserInterface' dates from when Windows 95 and NT4 were introduced
5691 // (at that time we still supported the old Windows 3.1 UI)
5692 // IsW95UserInterface = GetHKCU("General", "UseW95UserInterface", 1) != 0 ;
5693 IsW95UserInterface = true;
5694 info_render_complete = GetHKCU("Info", "RenderCompleteSound", 0) != 0 ;
5695
5696 SetupFrontend();
5697
5698 if (!IsW95UserInterface)
5699 {
5700 PVEnableMenuItem (CM_SHOWMAINWINDOW, MF_GRAYED) ;
5701 use_taskbar = false ;
5702 }
5703
5704 create_about_font () ;
5705
5706 InitializeCriticalSection (&critical_section) ;
5707
5708 GetHKCU("General", "CommandLine", "", old_command_line, sizeof (old_command_line)) ;
5709 strcpy (command_line, old_command_line) ;
5710
5711 // special case: POV may get associated with an arbitrary file type by the user.
5712 // in such cases we won't be given any verbs to indicate what to do with the file,
5713 // and in many instances our default action (which is to assume the file is either
5714 // SDL or INI) is not appropriate. so we make an exception here for such cases.
5715 //
5716 // if the sole command-line parameter is a QUOTED filename referring to a file which
5717 // exists, we assume /EDIT is desired (this may break some scripts that assume the
5718 // default; in such cases the script should explicitly pass /RENDER). the shell
5719 // always quotes files passed in this way; by testing for the quotes we can
5720 // eliminate some unnecessary tests.
5721 n = strlen(szCmdLine);
5722 if (n < _MAX_PATH && n > 2 && szCmdLine[0] == '"' && szCmdLine[n - 1] == '"')
5723 {
5724 memcpy(str, szCmdLine + 1, n - 2);
5725 str[n - 2] = '\0';
5726 if (fileExists(str))
5727 {
5728 FeatureNotify ("EditByDefault",
5729 "POV-Ray - Filename passed on command-line",
5730 "Quoted filenames which are the sole command-line parameter are now "
5731 "opened in the editor by default. If you wish to render them instead "
5732 "please pass the /RENDER switch (or provide more than one parameter).\n\n"
5733 "Click &Help for more information.",
5734 "associations", false) ;
5735 add_edit_file(str);
5736 szCmdLine = "";
5737 }
5738 }
5739
5740 if ((szCmdLine = preparse_commandline (szCmdLine)) != NULL)
5741 {
5742 if (benchmark_mode)
5743 demo_mode = false;
5744 if (parse_commandline (szCmdLine) > 1 && !demo_mode && !benchmark_mode)
5745 {
5746 restore_command_line = true ;
5747 strncpy (command_line, szCmdLine, sizeof (command_line) - 1) ;
5748 }
5749 }
5750
5751 if (debugging)
5752 if (_getcwd (str, sizeof (str) - 1) != NULL)
5753 debug_output("CWD is %s\n", str) ;
5754
5755 if (editors_enabled)
5756 {
5757 if (EditDLLPath != NULL)
5758 {
5759 sprintf (str, "%s" EDITDLLNAME, EditDLLPath) ;
5760 if (!LoadEditorDLL (str, false))
5761 use_editors = false ;
5762 }
5763 else
5764 {
5765 sprintf (str, "%s\\" EDITDLLNAME, modulePath) ;
5766 if (!LoadEditorDLL (str, true))
5767 {
5768 sprintf (str, "%sbin\\" EDITDLLNAME, BinariesPath) ;
5769 if (!LoadEditorDLL (str, false))
5770 use_editors = false ;
5771 }
5772 }
5773 }
5774 else
5775 use_editors = false;
5776
5777 GetHKCU("General", VERSIONVAL, "[unknown]", str, (DWORD) strlen (str)) ;
5778 if (debugging)
5779 debug_output("Registry records version %s, and we are %s\n", str, POV_RAY_VERSION COMPILER_VER SSE2_INCLUDED "." PVENGINE_VER) ;
5780
5781 if (strcmp (str, POV_RAY_VERSION COMPILER_VER "." PVENGINE_VER) != 0)
5782 {
5783 // we don't want to set the newVersion flag if the only thing that changed
5784 // was the compiler used to generate the binary. in this case we add an
5785 // explicit check for the intel, msvc, and watcom versions.
5786 if ((s = strstr (str, ".icl")) != NULL)
5787 strcpy (s, s + 4) ;
5788 else if ((s = strstr (str, ".msvc")) != NULL)
5789 strcpy (s, s + 5) ;
5790 else if ((s = strstr (str, ".watcom")) != NULL)
5791 strcpy (s, s + 7) ;
5792 // strip off any trailing digits from the compiler version
5793 if (s)
5794 while (isdigit (*s))
5795 strcpy (s, s + 1) ;
5796 if (strcmp (str, POV_RAY_VERSION "." PVENGINE_VER) != 0)
5797 newVersion = true ;
5798 }
5799
5800 if ((run_count = GetHKCU("General", "RunCount", 0)) == 0 || newVersion)
5801 {
5802 if (screen_depth < 8)
5803 {
5804 MessageBox (NULL,
5805 "NOTE : POV-Ray for Windows was not designed to run in 16-color mode. "
5806 "While the program will operate, it is recommended that you use a minimum "
5807 "graphics mode of 800x600x256.",
5808 "Warning - running in 16-color mode",
5809 MB_ICONEXCLAMATION) ;
5810 tile_background = false ;
5811 }
5812 if (screen_width < 800)
5813 {
5814 MessageBox (NULL,
5815 "NOTE : POV-Ray for Windows was not designed to run at less than 800x600.\n\n"
5816 "While the program will operate, it is recommended that you use a minimum "
5817 "graphics mode of 800x600x256.",
5818 "Warning - running at less than 800x600",
5819 MB_ICONEXCLAMATION) ;
5820 }
5821 }
5822 PutHKCU ("General", "RunCount", ++run_count) ;
5823
5824 if (screen_depth < 8)
5825 tile_background = false ;
5826
5827 /* Create the main window */
5828 placement = mainwin_placement ;
5829 placement.length = sizeof (WINDOWPLACEMENT) ;
5830 w = mainwin_placement.rcNormalPosition.right - mainwin_placement.rcNormalPosition.left ;
5831 h = mainwin_placement.rcNormalPosition.bottom - mainwin_placement.rcNormalPosition.top ;
5832 if (w <= 128)
5833 w = 700 ;
5834 if (h <= 128)
5835 h = screen_height - 75 ;
5836 main_window = CreateWindowEx (0,
5837 PovMainWinClass,
5838 "POV-Ray for Windows",
5839 WS_OVERLAPPEDWINDOW,
5840 mainwin_placement.rcNormalPosition.left,
5841 mainwin_placement.rcNormalPosition.top,
5842 w,
5843 h,
5844 NULL,
5845 NULL,
5846 hInst,
5847 NULL) ;
5848
5849 if (main_window == NULL)
5850 {
5851 MessageBox (NULL, "ERROR : Could not create main window.", "Critical Error", MB_ICONSTOP) ;
5852 cleanup_all () ;
5853 return (1) ;
5854 }
5855
5856 EditSetNotifyBase (main_window, CM_FIRSTEDITNOTIFY) ;
5857
5858 if ((StatusWindow = CreateStatusbar (main_window)) == NULL)
5859 {
5860 MessageBox (main_window, "ERROR : Could not create statusbar", "Critical Error", MB_ICONSTOP) ;
5861 cleanup_all () ;
5862 return (1) ;
5863 }
5864
5865 if (tile_background && background_file [1])
5866 {
5867 if ((hDIB = LoadDIB (background_file)) != NULL)
5868 {
5869 hBmpBackground = DIBToBitmap (hDIB, hPalApp) ;
5870 DeleteObject (hDIB) ;
5871 GetObject (hBmpBackground, sizeof (BITMAP), (LPSTR) &bm) ;
5872 background_width = bm.bmWidth ;
5873 background_height = bm.bmHeight ;
5874 }
5875 else
5876 {
5877 PovMessageBox ("Failed to load bitmap file", "Error") ;
5878 strcpy (background_file, "0") ;
5879 }
5880 }
5881
5882 if (tile_background && hBmpBackground == NULL && screen_depth >= 8)
5883 {
5884 if (isdigit (background_file [0]) && background_file [1] == '\0')
5885 id = background_file [0] - '0' ;
5886 SendMessage (main_window, WM_COMMAND, CM_BACKGROUNDSTD + id, 1L) ;
5887 }
5888
5889 if ((hBMP = LoadBitmap (hInstance, MAKEINTRESOURCE (BMP_ICON))) != NULL)
5890 hBmpIcon = hBMP ;
5891
5892 if (lastBitmapPath [0] == '\0')
5893 sprintf (lastBitmapPath, "%sTiles", BinariesPath) ;
5894 if (lastRenderPath [0] == '\0')
5895 {
5896 sprintf (lastRenderPath, "%sScenes\\Advanced", DocumentsPath) ;
5897 strcpy (lastRenderName, "Biscuit.pov") ;
5898 }
5899 if (lastQueuePath [0] == '\0')
5900 sprintf (lastQueuePath, "%sScenes", DocumentsPath) ;
5901 GetHKCU("Editor", "LastPath", "", str, sizeof (str)) ;
5902 validatePath (lastRenderPath) ;
5903 if (str [0] == '\0')
5904 PutHKCU("Editor", "LastPath", lastRenderPath) ;
5905 if (lastRenderName [0] != '\0' && !demo_mode && !benchmark_mode)
5906 joinPath (source_file_name, lastRenderPath, lastRenderName) ;
5907
5908 if (use_editors)
5909 if ((tab_window = InitialiseEditor (main_window, StatusWindow, BinariesPath, DocumentsPath)) == NULL)
5910 use_editors = false ;
5911
5912 message_window = CreateWindowEx (WS_EX_CLIENTEDGE,
5913 PovMessageWinClass,
5914 "",
5915 WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
5916 0,
5917 0,
5918 0,
5919 0,
5920 use_editors ? tab_window : main_window,
5921 NULL,
5922 hInst,
5923 NULL) ;
5924 if (message_window == NULL)
5925 {
5926 MessageBox (NULL, "ERROR : Could not create message window.", "Critical Error", MB_ICONSTOP) ;
5927 cleanup_all () ;
5928 return (1) ;
5929 }
5930
5931 if (initialise_message_display ())
5932 {
5933 cleanup_all () ;
5934 return (1) ;
5935 }
5936 EditSetMessageWindow (message_window) ;
5937
5938 if ((rebar_window = create_rebar (main_window)) == NULL)
5939 {
5940 MessageBox (main_window, "ERROR : Could not create internal window #1", "Critical Error", MB_ICONSTOP) ;
5941 cleanup_all () ;
5942 return (1) ;
5943 }
5944 if ((toolbar_window = create_toolbar (rebar_window)) == NULL)
5945 {
5946 MessageBox (main_window, "ERROR : Could not create internal window #2", "Critical Error", MB_ICONSTOP) ;
5947 cleanup_all () ;
5948 return (1) ;
5949 }
5950 if (!use_toolbar)
5951 {
5952 ShowWindow (rebar_window, SW_HIDE) ;
5953 toolheight = 0 ;
5954 }
5955 extract_ini_sections_ex (SecondaryRenderIniFileName, toolbar_combobox) ;
5956 SendMessage (toolbar_combobox, CB_ADDSTRING, 0, (LPARAM) "More Resolutions ...") ;
5957 tb_combo_sel = select_combo_item_ex (toolbar_combobox, SecondaryRenderIniFileSection) ;
5958 if (tb_combo_sel == -1)
5959 tb_combo_sel = 0 ;
5960
5961 setup_menus (use_editors) ;
5962 build_main_menu (hMainMenu, use_editors) ;
5963
5964 set_toggles () ;
5965
5966 if (!use_editors)
5967 {
5968 SendMessage (toolbar_window, TB_ENABLEBUTTON, CM_FILENEW, 0L) ;
5969 SendMessage (toolbar_window, TB_ENABLEBUTTON, CM_FILEOPEN, 0L) ;
5970 SendMessage (toolbar_window, TB_ENABLEBUTTON, CM_FILESAVE, 0L) ;
5971 }
5972 else
5973 EditRestoreState (!NoRestore) ;
5974
5975 if (editors_enabled)
5976 PVCheckMenuItem (CM_USEEDITOR, MF_CHECKED) ;
5977 PVEnableMenuItem (CM_RENDERHIDE, RenderwinIsChild ? MF_GRAYED : MF_ENABLED) ;
5978 PVEnableMenuItem (CM_RENDERACTIVE, RenderwinIsChild ? MF_GRAYED : MF_ENABLED) ;
5979 PVCheckMenuItem (on_completion, MF_CHECKED) ;
5980 PVEnableMenuItem (CM_RENDERSHOW, MF_GRAYED) ;
5981 PVEnableMenuItem (CM_RENDERSLEEP, MF_GRAYED) ;
5982
5983 PVCheckMenuRadioItem (CM_RENDERPRIORITY_BACKGROUND, CM_RENDERPRIORITY_HIGH, render_priority) ;
5984
5985 PVCheckMenuItem (drop_to_editor ? CM_DROPEDITOR : CM_DROPRENDERER, MF_CHECKED) ;
5986
5987 PVEnableMenuItem (CM_RENDERSHOW, MF_GRAYED) ;
5988 PVEnableMenuItem (CM_RENDERCLOSE, MF_GRAYED) ;
5989 PVModifyMenu (CM_TILEDBACKGROUND,
5990 MF_STRING,
5991 CM_TILEDBACKGROUND,
5992 tile_background ? "&Select Plain Background" : "&Select Tiled Background") ;
5993 PVCheckMenuRadioItem (CM_DUTYCYCLE_10, CM_DUTYCYCLE_100, CM_DUTYCYCLE_10 + Duty_Cycle) ;
5994 if (screen_depth < 8)
5995 {
5996 PVEnableMenuItem (CM_TILEDBACKGROUND, MF_GRAYED) ;
5997 PVEnableMenuItem (CM_BACKGROUNDBITMAP, MF_GRAYED) ;
5998 for (i = 0 ; i < 16 ; i++)
5999 PVEnableMenuItem (CM_BACKGROUNDSTD + i, MF_GRAYED) ;
6000 }
6001 set_newuser_menus (hide_newuser_help) ;
6002
6003 if (ThreadCount == 1)
6004 {
6005 PVDeleteMenuItem (CM_BENCHMARK) ;
6006 PVModifyMenu (CM_BENCHMARKONETHREAD, MF_STRING, CM_BENCHMARKONETHREAD, "Run &Benchmark") ;
6007 }
6008
6009 switch (placement.showCmd)
6010 {
6011 case SW_SHOWNORMAL :
6012 show_state = SW_SHOW ;
6013 break ;
6014
6015 case SW_SHOWMINIMIZED :
6016 // show_state = SW_SHOWMINNOACTIVE ;
6017 show_state = SW_SHOW ;
6018 break ;
6019
6020 case SW_SHOWMAXIMIZED :
6021 show_state = SW_SHOWMAXIMIZED ;
6022 break ;
6023
6024 default :
6025 show_state = SW_SHOW ;
6026 break ;
6027 }
6028
6029 if (ListenMode)
6030 show_state = SW_HIDE ;
6031
6032 placement.showCmd = show_state ;
6033 placement.flags = (placement.ptMinPosition.x == -1 && placement.ptMinPosition.y == -1) ? 0 : WPF_SETMINPOSITION ;
6034 if (placement.rcNormalPosition.right <= 0 || placement.rcNormalPosition.bottom <= 0)
6035 {
6036 placement.rcNormalPosition.right = placement.rcNormalPosition.left + message_xchar * 115 ;
6037 placement.rcNormalPosition.bottom = placement.rcNormalPosition.top + message_ychar * 75 ;
6038 }
6039
6040 placement.length = sizeof (WINDOWPLACEMENT) ;
6041 SetWindowPlacement (main_window, &placement) ;
6042 if (show_state != SW_SHOWMAXIMIZED)
6043 FitWindowInWindow (NULL, main_window) ;
6044
6045 if ((timer_id = SetTimer (main_window, 1, 250, NULL)) != 0)
6046 DragAcceptFiles (main_window, true) ;
6047
6048 // only needed for earlier versions of common control DLL ...
6049 if (use_toolbar && !IsComCtl5)
6050 {
6051 hDC = GetDC (toolbar_window) ;
6052 GetClientRect (toolbar_window, &rect) ;
6053 FillRect (hDC, &rect, (HBRUSH) GetStockObject (LTGRAY_BRUSH)) ;
6054 ReleaseDC (toolbar_window, hDC) ;
6055 }
6056
6057 // fixes visual glitch with ComCtl6
6058 if (use_toolbar && IsComCtl6)
6059 {
6060 hDC = GetDC (main_window) ;
6061 GetClientRect (rebar_window, &rect) ;
6062 FillRect (hDC, &rect, (HBRUSH) GetStockObject (LTGRAY_BRUSH)) ;
6063 ReleaseDC (main_window, hDC) ;
6064 }
6065
6066 if (ExtensionsEnabled)
6067 LoadGUIExtensions () ;
6068
6069 if (renderwin_left < 0 || renderwin_left > screen_width - 32 || renderwin_top < 0 || renderwin_top > screen_height - 32)
6070 {
6071 MONITORINFO mi;
6072 mi.cbSize = sizeof(MONITORINFO);
6073 if (GetMonitorInfo(MonitorFromWindow(main_window, MONITOR_DEFAULTTOPRIMARY), &mi))
6074 {
6075 // apply the principle of least astonishment: otherwise the render window could
6076 // turn up on a monitor which may be switched off or otherwise not being paid
6077 // attention to, with no (obvious) way for the user to move it. we make one
6078 // exception: if the render window is placed on the primary display, we won't
6079 // move it to the current display, since it's assumed the primary display is
6080 // always going to be visible.
6081 if (renderwin_left < mi.rcWork.left)
6082 renderwin_left = mi.rcWork.left ;
6083 if (renderwin_top < mi.rcWork.top)
6084 renderwin_top = mi.rcWork.top ;
6085 if (renderwin_left > mi.rcWork.right - 128)
6086 renderwin_left = mi.rcWork.right - 128 ;
6087 if (renderwin_top > mi.rcWork.bottom - 128)
6088 renderwin_top = mi.rcWork.bottom - 128 ;
6089 }
6090 }
6091
6092 buffer_message (mIDE, "Persistence of Vision Raytracer(tm) for Windows.\n") ;
6093 buffer_message (mIDE, "POV-Ray for Windows is part of the POV-Ray(tm) suite of programs.\n") ;
6094 buffer_message (mIDE, " This is version " POV_RAY_VERSION COMPILER_VER SSE2_INCLUDED "." PVENGINE_VER ".\n") ;
6095 buffer_message (mIDE, "Copyright 1991-2013 Persistence of Vision Raytracer Pty. Ltd.\n") ;
6096 buffer_message (mIDE, " " DISCLAIMER_MESSAGE_1 "\n") ;
6097 buffer_message (mIDE, " " DISCLAIMER_MESSAGE_2 "\n") ;
6098 buffer_message (mIDE, " Select Help|About (or press Alt+B) for more information and a copy of the license.\n") ;
6099 buffer_message (mIDE, "The terms POV-Ray and Persistence of Vision Raytracer are trademarks of\n") ;
6100 buffer_message (mIDE, " Persistence of Vision Raytracer Pty. Ltd.\n") ;
6101 if (render_bitmap_depth != 24)
6102 {
6103 buffer_message (mIDE, "\n") ;
6104 buffer_message (mIDE, renderwin_8bits ? "Using 8-bit dithered internal bitmap (menu setting)\n" :
6105 "Using 8-bit dithered internal bitmap (4 or 8-bit video mode)\n") ;
6106 }
6107
6108 buffer_message (mIDE, "\n") ;
6109 strcpy (tool_commands [0], "notepad.exe \"%ipovray.ini\"") ;
6110
6111 #if POV_RAY_IS_OFFICIAL != 1
6112 WIN_PrintOtherCredits () ;
6113 buffer_message (mIDE, "This unofficial build is derived from the POV-Ray for Windows source code.\n") ;
6114 #endif
6115 buffer_message (mDivider, "\n") ;
6116
6117 #if defined(USE_AVX_FMA4_FOR_NOISE)
6118 // technically we should ask the backend what it's using, but given this is not a remoted version
6119 // of POVWIN, we just call the test here.
6120 if (CPU_FMA4_DETECT() != 0)
6121 {
6122 buffer_message (mIDE, "FMA4 instruction support detected: using FMA4-optimized noise functions.\n") ;
6123 buffer_message (mDivider, "\n") ;
6124 }
6125 #endif
6126
6127 load_tool_menu (ToolIniFileName) ;
6128 if (GetHKCU("FileQueue", "ReloadOnStartup", 0))
6129 {
6130 queued_file_count = GetHKCU("FileQueue", "QueueCount", 0) ;
6131 if (queued_file_count > MAX_QUEUE)
6132 queued_file_count = MAX_QUEUE ;
6133 for (i = 0 ; i < queued_file_count ; i++)
6134 {
6135 sprintf (str, "QueuedFile%d", i) ;
6136 GetHKCU("FileQueue", str, "", queued_files [i], sizeof (queued_files [0])) ;
6137 }
6138 if (queued_file_count != 0)
6139 message_printf ("Loaded %d entr%s into file queue\n", queued_file_count, queued_file_count == 1 ? "y" : "ies") ;
6140 update_queue_status (false) ;
6141 }
6142
6143 if (have_cpu_info)
6144 message_printf("Detected %u CPU%s providing %u physical core%s and %u logical one%s.\n",
6145 NumPhysicalCPUs, NumPhysicalCPUs > 1 ? "'s" : "",
6146 NumCPUCores, NumCPUCores > 1 ? "s" : "",
6147 NumLogicalCPUs, NumLogicalCPUs > 1 ? "s" : "");
6148
6149 buffer_message (mDivider, "\n") ;
6150
6151 if (GetHKCU("General", "CheckColorsInc", 1) == 1)
6152 {
6153 sprintf (str, "%sinclude\\colors.inc", DocumentsPath) ;
6154 if (stat (str, &statbuf) != 0)
6155 {
6156 char temp[2048];
6157 sprintf(temp,
6158 "WARNING : Cannot find COLORS.INC in expected location:\n\n%s\n\n"
6159 "This file is important for the normal operation of POV-Ray. It is included "
6160 "with the POV-Ray for Windows distribution. If you did not install using the "
6161 "correct installation procedure please attend to this before running POV-Ray "
6162 "for Windows.\n\nIf, however, you have chosen to change the location of this file "
6163 "or do not need it, you may ignore this warning as long as you have updated "
6164 "POVRAY.INI to the new path, or do not use any standard scenes that require it.\n\n"
6165 "Do you want to see this warning again ?",
6166 str);
6167 if (MessageBox (NULL, temp, "Warning - COLORS.INC is missing", MB_ICONEXCLAMATION | MB_YESNO) == IDNO)
6168 PutHKCU ("General", "CheckColorsInc", 0U) ;
6169 }
6170 }
6171
6172 if (demo_mode)
6173 {
6174 message_printf ("Running demonstration\n") ;
6175 argc = 0 ;
6176 handle_main_command (CM_DEMO, 0) ;
6177 }
6178
6179 if (benchmark_mode)
6180 {
6181 message_printf ("Running benchmark\n") ;
6182 argc = 0 ;
6183 handle_main_command (CM_BENCHMARK, 0) ;
6184 }
6185
6186 SendMessage (toolbar_cmdline, WM_SETTEXT, 0, (LPARAM) command_line) ;
6187
6188 if (debugging)
6189 {
6190 message_printf ("My window handle is %p\n", main_window) ;
6191
6192 if (HaveWin95OrLater ())
6193 message_printf ("Win95 or later detected\n") ;
6194 if (HaveWin98OrLater ())
6195 message_printf ("Win98 or later detected\n") ;
6196 if (HaveNT4OrLater ())
6197 message_printf ("WinNT or later detected\n") ;
6198 if (HaveWin2kOrLater ())
6199 message_printf ("Win2k or later detected\n") ;
6200 if (HaveWinXPOrLater ())
6201 message_printf ("WinXP or later detected\n") ;
6202 if (IsW95UserInterface)
6203 message_printf ("Windows 95 user interface flag is set\n") ;
6204 }
6205
6206 for (i = 0 ; i < EditFileCount ; i++)
6207 {
6208 if (EditGetFlags () & EDIT_CAN_OPEN)
6209 EditOpenFile (EditFiles [i]) ;
6210 free (EditFiles [i]) ;
6211 EditFiles [i] = NULL ;
6212 }
6213 EditFileCount = 0 ;
6214
6215 if (newVersion || FreshInstall)
6216 {
6217 if (EditGetFlags() & EDIT_CAN_OPEN)
6218 {
6219 sprintf(str, "%srevision.txt", DocumentsPath);
6220 if (fileExists(str))
6221 EditOpenFile(str) ;
6222 if (EditGetFlags() & EDIT_CAN_OPEN)
6223 {
6224 sprintf(str, "%schanges.txt", DocumentsPath);
6225 if (fileExists(str))
6226 EditOpenFile(str) ;
6227 }
6228 }
6229
6230 // TODO: remove this after a few betas
6231 tile_background = false;
6232 text_colours[0] = RGB (255, 255, 255);
6233 text_colours[1] = RGB (255, 255, 0);
6234 text_colours[2] = RGB (0, 255, 255);
6235 background_colour = RGB (31, 0, 63);
6236 }
6237
6238 if (run_count > 1 && !demo_mode && !benchmark_mode)
6239 {
6240 n = GetHKCU("General", "ItsAboutTime", 0) ;
6241 if (_time32 (NULL) > n /*|| newVersion*/)
6242 {
6243 ShowAboutBox () ;
6244 PutHKCU ("General", "ItsAboutTime", n ? _time32 (NULL) + DAYS(14) : _time32 (NULL) + DAYS(1)) ;
6245 }
6246 }
6247
6248 #if POV_RAY_IS_OFFICIAL == 1
6249 DoUpdateCheck () ;
6250 #endif
6251
6252 // automatically call the rendering engine if there were any parameters on the command line
6253 if (!rendering && (argc > 1 || render_requested))
6254 {
6255 if (render_requested)
6256 {
6257 wrapped_printf ("Requested render file is '%s'", requested_render_file) ;
6258 strcpy (source_file_name, requested_render_file) ;
6259 }
6260 if (argc > 1)
6261 wrapped_printf ("Calling rendering engine with parameters '%s'", command_line) ;
6262 start_rendering (!render_requested) ;
6263 }
6264
6265 if (homeInferred)
6266 message_printf ("Warning: running with inferred home path due to missing registry entry.\n\n") ;
6267
6268 #ifdef _DEBUG
6269 if (sizeof (ExternalVarStruct) != 0x9350)
6270 PovMessageBox ("Compatibility problem - ExternalVarStruct has changed size", "Warning") ;
6271 #endif
6272
6273 if (ListenMode)
6274 handle_main_command (CM_SHOWMAINWINDOW, 0) ;
6275
6276 if (debugging)
6277 debug_output("Entering GetMessage loop\n") ;
6278
6279 try
6280 {
6281 while (!exit_loop)
6282 {
6283 // since the render thread can really slow things down for the UI (this becomes
6284 // a problem if the user sets the render priority to high and then finds the
6285 // UI unresponsive when attempting to change it back), we only sleep here if
6286 // there's no events in the queue that we feel the need to handle immediately.
6287 // (if one of these messages turns up while we're sleeping we'll get woken).
6288 // N.B. longer wait times resulted in complaints from some testers, apparently
6289 // there's some machines out there that don't exit the wait for some types of
6290 // input.
6291 MsgWaitForMultipleObjects (0, NULL, FALSE, 10, QS_ALLINPUT) ;
6292 // MsgWaitForMultipleObjects (0, NULL, FALSE, 10, QS_HOTKEY | QS_KEY | QS_MOUSEBUTTON) ;
6293
6294 if (StartInsertRender)
6295 {
6296 if (!rendering)
6297 start_rendering (false) ;
6298 StartInsertRender = false ;
6299 }
6300
6301 if (quit != 0)
6302 if (quit + 15 < time (NULL))
6303 break ;
6304
6305 ProcessSession();
6306 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
6307 {
6308 if (msg.message == WM_QUIT)
6309 {
6310 exit_loop = true ;
6311 break ;
6312 }
6313
6314 // we have to disable all these calls because HTML Help has a bug (on some
6315 // platforms - I can't work out the exact conditions that trigger it) which
6316 // will cause the cursor to flash between normal and the busy state (normally
6317 // an hourglass) several times a second, continually (even if help isn't open).
6318 // See job #124.
6319 #ifdef HTMLHELP_FIXED
6320 if (HtmlHelp (NULL, NULL, HH_PRETRANSLATEMESSAGE, (DWORD) &msg))
6321 continue ;
6322 #else
6323 // we need to pass on these messages, otherwise help navigation messages
6324 // will go to us instead of the help window
6325 if (msg.message == WM_KEYDOWN || msg.message == WM_SYSKEYDOWN)
6326 if (!IsChild (main_window, msg.hwnd))
6327 if (HtmlHelp (NULL, NULL, HH_PRETRANSLATEMESSAGE, (DWORD_PTR) &msg))
6328 continue ;
6329 #endif
6330 if (!TranslateAccelerator (main_window, hAccelerators, &msg))
6331 {
6332 TranslateMessage (&msg) ;
6333 if (msg.hwnd == toolbar_cmdline)
6334 {
6335 if (msg.message == WM_CHAR)
6336 if (handle_toolbar_cmdline (msg.wParam, msg.lParam))
6337 continue ;
6338 }
6339 DispatchMessage (&msg) ;
6340 }
6341 ProcessSession();
6342 }
6343 }
6344 }
6345 catch(std::exception& e)
6346 {
6347 sprintf (str, "Caught exception: %s", e.what()) ;
6348 if (debugging)
6349 debug_output ("%s\n", str) ;
6350 MessageBox (NULL, str, "POV-Ray Critical Error", MB_ICONSTOP) ;
6351 exit(1);
6352 }
6353
6354 if (debugging)
6355 debug_output ("Dropping out of message loop\n") ;
6356
6357 try
6358 {
6359 DeleteFrontend();
6360 cleanup_all () ;
6361 }
6362 catch(pov_base::Exception& e)
6363 {
6364 // don't do much about POV exceptions here: often, they will relate to the front end
6365 // not cleaning up fast enough (i.e. due to a lot of memory de-allocation)
6366 if (debugging)
6367 debug_output ("Caught exception: %s\n", e.what()) ;
6368 }
6369 catch(std::exception& e)
6370 {
6371 sprintf (str, "Caught exception: %s", e.what()) ;
6372 if (debugging)
6373 debug_output ("%s\n", str) ;
6374 MessageBox (NULL, str, "POV-Ray Critical Error", MB_ICONSTOP) ;
6375 }
6376
6377 _fcloseall () ;
6378 #ifndef _WIN64
6379 // win64 - get exception during HH_UNINITIALIZE
6380 HtmlHelp (NULL, NULL, HH_UNINITIALIZE, (DWORD) help_cookie) ;
6381 #endif
6382
6383 if (debugging)
6384 debug_output ("exiting WinMain()\n") ;
6385 return (0) ;
6386 }
6387