1 /* -*- mode: C++; tab-width: 4; c-basic-offset: 4; -*- */
2 
3 /* AbiWord
4  * Copyright (C) 1998-2000 AbiSource, Inc.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19  * 02110-1301 USA.
20  */
21 
22 /*****************************************************************
23 ** Only one of these is created by the application.
24 *****************************************************************/
25 
26 #define WIN32_LEAN_AND_MEAN
27 
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31 
32 #include <stdlib.h>
33 #include <windows.h>
34 #include <commctrl.h>   // includes the common control header
35 #ifdef _MSC_VER
36 #include <crtdbg.h>
37 #endif
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 
41 #include <stdio.h>
42 #include <string.h>
43 #include <io.h>
44 #include <fcntl.h>
45 
46 #if !defined(__WINE__) && (!defined(_MSC_VER) || _MSC_VER < 1310) && !defined(__MINGW32__)
47 #include <iostream.h>
48 #elif _MSC_VER >= 1310
49 #include <iostream>
50 #endif
51 
52 #include <ole2.h>
53 
54 #include "ut_debugmsg.h"
55 #include "ut_bytebuf.h"
56 #include "ut_string.h"
57 #include "xap_Args.h"
58 #include "ap_Args.h"
59 #include "ap_Convert.h"
60 #include "ap_Win32Frame.h"
61 #include "ap_Win32App.h"
62 #include "spell_manager.h"
63 
64 #include "ap_Strings.h"
65 #include "ap_LoadBindings.h"
66 #include "xap_EditMethods.h"
67 #include "xap_Menu_Layouts.h"
68 #include "xap_Menu_ActionSet.h"
69 #include "xap_Toolbar_ActionSet.h"
70 #include "xap_EncodingManager.h"
71 #include "xap_ModuleManager.h"
72 #include "ev_EditMethod.h"
73 #include "xap_Module.h"
74 #include "abi-builtin-plugins.h"
75 
76 #include "ap_Win32Resources.rc2"
77 #include "ap_Clipboard.h"
78 #include "ap_EditMethods.h"
79 
80 #include "fp_Run.h"
81 #include "ut_path.h"
82 #include "ut_Win32OS.h"
83 #include "ut_Win32Idle.h"
84 #include "ut_Language.h"
85 #include "ut_Win32LocaleString.h"
86 
87 #include "ie_impexp_Register.h"
88 
89 #include "ie_exp.h"
90 #include "ie_exp_RTF.h"
91 #include "ie_exp_Text.h"
92 
93 #include "ie_imp.h"
94 #include "ie_imp_RTF.h"
95 #include "ie_imp_Text.h"
96 #include "ie_impGraphic.h"
97 #include "fg_Graphic.h"
98 #include "xav_View.h"
99 #include "xad_Document.h"
100 #include "ap_FrameData.h"
101 #include "ut_Win32Locale.h"
102 
103 #include "ap_Strings.h"
104 
105 #include "pt_PieceTable.h"
106 
107 #include "gr_Painter.h"
108 // extern prototype - this is defined in ap_EditMethods.cpp
109 extern XAP_Dialog_MessageBox::tAnswer s_CouldNotLoadFileMessage(XAP_Frame * pFrame, const char * pNewFile, UT_Error errorCode);
110 /*****************************************************************/
111 
AP_Win32App(HINSTANCE hInstance,const char * szAppName)112 AP_Win32App::AP_Win32App(HINSTANCE hInstance, const char * szAppName)
113 	: AP_App(hInstance, szAppName)
114 {
115 	m_pStringSet = NULL;
116 	m_pClipboard = NULL;
117 }
118 
~AP_Win32App(void)119 AP_Win32App::~AP_Win32App(void)
120 {
121 	DELETEP(m_pStringSet);
122 	DELETEP(m_pClipboard);
123 
124 	IE_ImpExp_UnRegisterXP ();
125 }
126 
s_createDirectoryIfNecessary(const char * szDir)127 static bool s_createDirectoryIfNecessary(const char * szDir)
128 {
129 	struct _stat statbuf;
130 	UT_Win32LocaleString str;
131 
132 	str.fromUTF8(szDir);
133 
134 	if (_wstat(str.c_str(),&statbuf) == 0)								// if it exists
135 	{
136 		if ( (statbuf.st_mode & _S_IFDIR) == _S_IFDIR )			// and is a directory
137 			return true;
138 
139 		UT_DEBUGMSG(("Pathname [%s] is not a directory.\n",szDir));
140 		return false;
141 	}
142 
143 	if (CreateDirectoryW(str.c_str(),NULL))
144 		return true;
145 
146 	UT_DEBUGMSG(("Could not create Directory [%s].\n",szDir));
147 	return false;
148 }
149 
150 typedef BOOL __declspec(dllimport) (CALLBACK *InitCommonControlsEx_fn)(LPINITCOMMONCONTROLSEX lpInitCtrls);
151 
initialize(void)152 bool AP_Win32App::initialize(void)
153 {
154 	bool bSuccess = true;
155 	const char * szUserPrivateDirectory = getUserPrivateDirectory();
156 	bool bVerified = s_createDirectoryIfNecessary(szUserPrivateDirectory);
157 
158 	UT_return_val_if_fail (bVerified, false);
159 
160 	// create templates directory
161 	UT_String sTemplates = szUserPrivateDirectory;
162 	sTemplates += "/templates";
163 	s_createDirectoryIfNecessary(sTemplates.c_str());
164 
165 	// load the preferences.
166 
167 	m_prefs = new AP_Win32Prefs();
168 	UT_return_val_if_fail (m_prefs, false);
169 
170 	m_prefs->fullInit();
171 
172 	// now that preferences are established, let the xap init
173 
174 	m_pClipboard = new AP_Win32Clipboard();
175 	UT_return_val_if_fail (m_pClipboard, false);
176 
177 	m_pEMC = AP_GetEditMethods();
178 	UT_return_val_if_fail (m_pEMC, false);
179 
180 	m_pBindingSet = new AP_BindingSet(m_pEMC);
181 	UT_return_val_if_fail (m_pBindingSet, false);
182 
183 	m_pMenuActionSet = AP_CreateMenuActionSet();
184 	UT_return_val_if_fail (m_pMenuActionSet,false);
185 
186 	m_pToolbarActionSet = AP_CreateToolbarActionSet();
187 	UT_return_val_if_fail (m_pToolbarActionSet,false);
188 
189 	//////////////////////////////////////////////////////////////////
190 	// load the dialog and message box strings
191 	//////////////////////////////////////////////////////////////////
192 
193 	{
194 		// assume we will be using the builtin set (either as the main
195 		// set or as the fallback set).
196 
197 		AP_BuiltinStringSet * pBuiltinStringSet = new AP_BuiltinStringSet(this,AP_PREF_DEFAULT_StringSet);
198 		UT_return_val_if_fail (pBuiltinStringSet, false);
199 		m_pStringSet = pBuiltinStringSet;
200 
201 		// see if we should load an alternate set from the disk
202 
203 		const char * szDirectory = NULL;
204 		const char * szStringSet = NULL;
205 
206 		if (   (getPrefsValue(AP_PREF_KEY_StringSet,&szStringSet))
207 			&& (szStringSet)
208 			&& (*szStringSet)
209 			&& (g_ascii_strcasecmp(szStringSet,AP_PREF_DEFAULT_StringSet) != 0))
210 		{
211 			getPrefsValueDirectory(true,AP_PREF_KEY_StringSetDirectory,&szDirectory);
212 			UT_return_val_if_fail ((szDirectory) && (*szDirectory), false);
213 
214 			char * szPathname = (char *)UT_calloc(sizeof(char),strlen(szDirectory)+strlen(szStringSet)+100);
215 			UT_return_val_if_fail (szPathname, false);
216 
217 			sprintf(szPathname,"%s%s%s.strings",
218 					szDirectory,
219 					((szDirectory[strlen(szDirectory)-1]=='\\') ? "" : "\\"),
220 					szStringSet);
221 
222 			AP_DiskStringSet * pDiskStringSet = new AP_DiskStringSet(this);
223 			UT_return_val_if_fail (pDiskStringSet, false);
224 
225 			if (pDiskStringSet->loadStringsFromDisk(szPathname))
226 			{
227 				pDiskStringSet->setFallbackStringSet(m_pStringSet);
228 				m_pStringSet = pDiskStringSet;
229 				UT_Language_updateLanguageNames();
230 				UT_DEBUGMSG(("Using StringSet [%s]\n",szPathname));
231 			}
232 			else
233 			{
234 				UT_DEBUGMSG(("Unable to load StringSet [%s] -- using builtin strings instead.\n",szPathname));
235 				DELETEP(pDiskStringSet);
236 			}
237 
238 			g_free(szPathname);
239 		}
240 	}
241 
242 	// AP_App::initilize() calls for us XAP_Win32App::initialize()
243 	if (! AP_App::initialize())
244 		return false;
245 
246 
247 	// let various window types register themselves
248 
249 	if (!AP_Win32Frame::RegisterClass(this))
250 	{
251 		UT_DEBUGMSG(("couldn't register class\n"));
252 		return false;
253 	}
254 
255 	//////////////////////////////////////////////////////////////////
256 	// Initialize the importers/exporters
257 	//////////////////////////////////////////////////////////////////
258 	IE_ImpExp_RegisterXP ();
259 
260 	//////////////////////////////////////////////////////////////////
261 	// initializes the spell checker.
262 	//////////////////////////////////////////////////////////////////
263 
264 	{
265 #if ENABLE_SPELL
266 		SpellManager::instance();
267 #endif
268 	}
269 
270 
271 	// Now we have the strings loaded we can populate the field names correctly
272 	int i;
273 
274 	for (i = 0; fp_FieldTypes[i].m_Type != FPFIELDTYPE_END; i++)
275 	{
276 	    (&fp_FieldTypes[i])->m_Desc = m_pStringSet->getValue(fp_FieldTypes[i].m_DescId);
277 	    UT_DEBUGMSG(("Setting field type desc for type %d, desc=%s\n", fp_FieldTypes[i].m_Type, fp_FieldTypes[i].m_Desc));
278 	}
279 
280 	for (i = 0; fp_FieldFmts[i].m_Tag != NULL; i++)
281 	{
282 	    (&fp_FieldFmts[i])->m_Desc = m_pStringSet->getValue(fp_FieldFmts[i].m_DescId);
283 	    UT_DEBUGMSG(("Setting field desc for field %s, desc=%s\n", fp_FieldFmts[i].m_Tag, fp_FieldFmts[i].m_Desc));
284 	}
285 
286     ///////////////////////////////////////////////////////////////////////
287     /// Build a labelset so the plugins can add themselves to something ///
288     ///////////////////////////////////////////////////////////////////////
289 
290 	const char * szMenuLabelSetName = NULL;
291 	if (getPrefsValue( AP_PREF_KEY_StringSet, (const gchar**)&szMenuLabelSetName)
292 		&& (szMenuLabelSetName) && (*szMenuLabelSetName))
293 	{
294 		;
295 	}
296 	else
297 		szMenuLabelSetName = AP_PREF_DEFAULT_StringSet;
298 
299 	getMenuFactory()->buildMenuLabelSet(szMenuLabelSetName);
300 
301 	//////////////////////////////////////////////////////////////////
302 	// Check for necessary DLLs now that we can do localized error messages
303 	//////////////////////////////////////////////////////////////////
304 
305 	// Ensure that common control DLL is loaded
306 	HINSTANCE hinstCC = LoadLibraryW(L"comctl32.dll");
307 	UT_return_val_if_fail (hinstCC, false);
308 	InitCommonControlsEx_fn  pInitCommonControlsEx = NULL;
309 	if( hinstCC != NULL )
310 		pInitCommonControlsEx = (InitCommonControlsEx_fn)GetProcAddress( hinstCC, "InitCommonControlsEx");
311 	if( pInitCommonControlsEx != NULL )
312 	{
313 		INITCOMMONCONTROLSEX icex;
314 		icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
315 		icex.dwICC = ICC_COOL_CLASSES | ICC_BAR_CLASSES 	// load the rebar and toolbar
316 					| ICC_TAB_CLASSES | ICC_UPDOWN_CLASS	// and tab and spin controls
317 					| ICC_STANDARD_CLASSES;
318 		pInitCommonControlsEx(&icex);
319 	}
320 	else
321 	{
322 		InitCommonControls();
323 
324 		UT_Win32LocaleString err;
325 		err.fromUTF8 (m_pStringSet->getValue(AP_STRING_ID_WINDOWS_COMCTL_WARNING));
326 		MessageBoxW(NULL, err.c_str(), NULL, MB_OK);
327 	}
328 
329 	//////////////////////////////////////////////////////////////////
330 	// load the all Plugins from the correct directory
331 	//////////////////////////////////////////////////////////////////
332 
333 #ifndef DISABLE_BUILTIN_PLUGINS
334 	abi_register_builtin_plugins();
335 #endif
336 
337 	bool bLoadPlugins = true;
338 	bool bFound = getPrefsValueBool(XAP_PREF_KEY_AutoLoadPlugins,&bLoadPlugins);
339 
340 	if(bLoadPlugins || !bFound)
341 	{
342 		WCHAR szPath[PATH_MAX];
343 		WCHAR szPlugin[PATH_MAX];
344 		_getExeDir( szPath, PATH_MAX);
345 #ifdef _MSC_VER
346 		lstrcatW(szPath, L"..\\plugins\\*.dll");
347 #else
348 #define ABI_WIDE_STRING(t) L ## t
349 		lstrcatW(szPath, ABI_WIDE_STRING("..\\lib\\" PACKAGE L"-" ABIWORD_SERIES L"\\plugins\\*.dll"));
350 #endif
351 
352 		WIN32_FIND_DATAW cfile;
353 		HANDLE findtag = FindFirstFileW( szPath, &cfile );
354 		if( findtag != INVALID_HANDLE_VALUE )
355 		{
356 			do
357 			{
358 				_getExeDir( szPlugin, PATH_MAX );
359 #ifdef _MSC_VER
360 				lstrcatW( szPlugin, L"..\\plugins\\" );
361 #else
362 				lstrcatW( szPlugin, ABI_WIDE_STRING("..\\lib\\" PACKAGE L"-" ABIWORD_SERIES L"\\plugins\\" ));
363 #endif
364 				lstrcatW( szPlugin, cfile.cFileName );
365 				XAP_ModuleManager::instance().loadModule( getUTF8String(szPlugin) );
366 			} while( FindNextFileW ( findtag, &cfile ) );
367 			FindClose( findtag );
368 		}
369 
370 		UT_String pluginName( getUserPrivateDirectory() );
371 		UT_String pluginDir( getUserPrivateDirectory() );
372 		pluginDir += "\\AbiWord\\plugins\\*.dll";
373 		UT_Win32LocaleString str;
374 		str.fromUTF8(pluginDir.c_str());
375 		findtag = FindFirstFileW( str.c_str(), &cfile );
376 		if( findtag != INVALID_HANDLE_VALUE )
377 		{
378 			do
379 			{
380 				pluginName = getUserPrivateDirectory();
381 				pluginName += "\\AbiWord\\plugins\\";
382 				pluginName += getUTF8String(cfile.cFileName);
383 				XAP_ModuleManager::instance().loadModule( pluginName.c_str() );
384 			} while( FindNextFileW( findtag, &cfile ) );
385 			FindClose( findtag );
386 		}
387 	}
388 	return bSuccess;
389 }
390 
391 
392 // if app is NULL then we use 'this'
newFrame(void)393 XAP_Frame * AP_Win32App::newFrame(void)
394 {
395 	AP_Win32Frame * pWin32Frame = new AP_Win32Frame();
396 
397 	if (pWin32Frame)
398 		pWin32Frame->initialize();
399 
400 	return pWin32Frame;
401 }
402 
403 
shutdown(void)404 bool AP_Win32App::shutdown(void)
405 {
406 	if (m_prefs->getAutoSavePrefs())
407 		m_prefs->savePrefsFile();
408 
409 	delete m_prefs;
410 	m_prefs = NULL;
411 
412 	return true;
413 }
414 
getPrefsValueDirectory(bool bAppSpecific,const gchar * szKey,const gchar ** pszValue) const415 bool AP_Win32App::getPrefsValueDirectory(bool bAppSpecific,
416 											const gchar * szKey, const gchar ** pszValue) const
417 {
418 	if (!m_prefs)
419 		return false;
420 
421 	const gchar * psz = NULL;
422 	if (!m_prefs->getPrefsValue(szKey,&psz))
423 		return false;
424 
425 	if ((*psz == '/') || (*psz == '\\'))
426 	{
427 		*pszValue = psz;
428 		return true;
429 	}
430 
431 	const gchar * dir = ((bAppSpecific) ? getAbiSuiteAppDir() : getAbiSuiteLibDir());
432 
433 	static gchar buf[1024];
434 	UT_return_val_if_fail ((strlen(dir) + strlen(psz) + 2) < sizeof(buf), false);
435 
436 	sprintf(buf,"%s\\%s",dir,psz);
437 	*pszValue = buf;
438 	return true;
439 }
440 
getAbiSuiteAppDir(void) const441 const char * AP_Win32App::getAbiSuiteAppDir(void) const
442 {
443     return getAbiSuiteLibDir();
444 }
445 
getIcon(void)446 HICON AP_Win32App::getIcon(void)
447 {
448 
449 	int sy = GetSystemMetrics(SM_CYICON);
450 	int sx = GetSystemMetrics(SM_CXICON);
451 	UT_DEBUGMSG(("GetIcon(): system metrics [%d %d]\n",sx,sy));
452 
453 	if ((sx==32) && (sy==32))
454 		return LoadIconW(getInstance(), MAKEINTRESOURCEW(AP_RID_ICON_APPLICATION_32));
455 	else
456 		return (HICON) LoadImageW(getInstance(), MAKEINTRESOURCEW(AP_RID_ICON_APPLICATION_32), IMAGE_ICON, 0,0,0);
457 }
458 
getSmallIcon(void)459 HICON AP_Win32App::getSmallIcon(void)
460 {
461 
462 	int sy = GetSystemMetrics(SM_CYICON);
463 	int sx = GetSystemMetrics(SM_CXICON);
464 	UT_DEBUGMSG(("GetIcon(): system metrics [%d %d]\n",sx,sy));
465 
466 	if ((sx==16) && (sy==16))
467 		return LoadIconW(getInstance(), MAKEINTRESOURCEW(AP_RID_ICON_APPLICATION_16));
468 	else
469 		return (HICON) LoadImageW(getInstance(), MAKEINTRESOURCEW(AP_RID_ICON_APPLICATION_16), IMAGE_ICON, 0,0,0);
470 }
471 
getStringSet(void) const472 const XAP_StringSet * AP_Win32App::getStringSet(void) const
473 {
474 	return m_pStringSet;
475 }
476 
477 #ifdef COPY_ON_DEMAND
478 /*!
479     indicate to the clipboard that we can provide data in this format
480     on demand
481 */
_indicateFmtToClipboard(const char * pszFmt) const482 void AP_Win32App::_indicateFmtToClipboard(const char * pszFmt) const
483 {
484 	UT_return_if_fail(m_pClipboard && pszFmt);
485 	UINT iFmt = m_pClipboard->convertFormatString(pszFmt);
486 
487 	SetClipboardDataW(iFmt, NULL);
488 }
489 
_cacheClipboardDoc(PD_DocumentRange * pDocRange)490 bool AP_Win32App::_cacheClipboardDoc(PD_DocumentRange *pDocRange)
491 {
492 	UT_return_val_if_fail(m_pClipboard && pDocRange, false);
493 
494 	UT_ByteBuf buf;
495 	UT_Error status;;
496 	UT_Byte b = 0;
497 
498 	IE_Exp_RTF * pExpRtf = new IE_Exp_RTF(pDocRange->m_pDoc);
499 	if (pExpRtf)
500 	{
501 		status = pExpRtf->copyToBuffer(pDocRange,&buf);
502 
503 		if(status != UT_OK)
504 			return false;
505 
506 		buf.append(&b,1);			// NULL terminate the string
507 		DELETEP(pExpRtf);
508 	}
509 	else
510 	{
511 		return false;
512 	}
513 
514 	// now create a subdocument ...
515 	PD_Document * pDoc = new PD_Document();
516 
517 	if(!pDoc)
518 		return false;
519 
520 	pDoc->newDocument();
521 
522 	PD_DocumentRange DocRange(pDoc, 2, 2);
523 
524 	IE_Imp * pImp = 0;
525 	IE_Imp::constructImporter(pDoc, IE_Imp::fileTypeForSuffix(".rtf"),&pImp,0);
526 
527 	if(pImp)
528 	{
529 		pImp->pasteFromBuffer(&DocRange,buf.getPointer(0),buf.getLength(),NULL);
530 		delete pImp;
531 	}
532 	else
533 	{
534 		return false;
535 	}
536 
537 	m_pClipboard->setClipboardDoc(pDoc);
538 	return true;
539 }
540 
541 /*!
542     copy the required format to the clipboard on demand
543     see docs on WM_RENDERFORMAT
544 */
copyFmtToClipboardOnDemand(UINT iFmt)545 bool AP_Win32App::copyFmtToClipboardOnDemand(UINT iFmt)
546 {
547 	UT_return_val_if_fail(m_pClipboard, false);
548 
549 	PD_DocumentRange DocRange;
550 	DocRange.m_pDoc = m_pClipboard->getClipboardDoc();
551 	UT_return_val_if_fail(DocRange.m_pDoc, false);
552 
553 	DocRange.m_pos1 = 2;
554 	DocRange.m_pos2 = DocRange.m_pDoc->getLastFrag()->getPos() + DocRange.m_pDoc->getLastFrag()->getLength();
555 
556 	if(!_copyFmtToClipboard(&DocRange, iFmt))
557 		return false;
558 
559 	return true;
560 }
561 
562 /*!
563     copy data to the clipboard in all formats on demand (this is
564     called when application is exiting and leaving data on clipboard
565     that and indicating that data in addtional formats is available
566     see docs on WM_RENDERALLFORMATS
567 */
copyAllFmtsToClipboardOnDemand()568 bool AP_Win32App::copyAllFmtsToClipboardOnDemand()
569 {
570 	UT_return_val_if_fail(m_pClipboard, false);
571 
572 	// I will use NULL here, since we are about to shut down anyway ...
573 	if(!m_pClipboard->openClipboard(NULL))			// try to lock the clipboard
574 		return false;
575 
576 	// need to clear clipboard in order to become its owners
577 	m_pClipboard->clearClipboard();
578 
579 	// what we need is to get the data from the clipboard and convert
580 	// it to the format requested
581 	PD_DocumentRange DocRange;
582 	DocRange.m_pDoc = m_pClipboard->getClipboardDoc();
583 	UT_return_val_if_fail(DocRange.m_pDoc, false);
584 
585 	DocRange.m_pos1 = 2;
586 	DocRange.m_pos2 = DocRange.m_pDoc->getLastFrag()->getPos() + DocRange.m_pDoc->getLastFrag()->getLength();
587 
588 	_copyFmtToClipboard(&DocRange, AP_CLIPBOARD_RTF);
589 	_copyFmtToClipboard(&DocRange, AP_CLIPBOARD_TEXTPLAIN_UCS2);
590 	_copyFmtToClipboard(&DocRange, AP_CLIPBOARD_TEXTPLAIN_8BIT);
591 
592 	return true;
593 }
594 
595 #endif // COPY_ON_DEMAND
596 
597 /*!
598     copy data in required format to the clipboard
599 */
_copyFmtToClipboard(PD_DocumentRange * pDocRange,UINT iFmt)600 bool AP_Win32App::_copyFmtToClipboard(PD_DocumentRange * pDocRange, UINT iFmt)
601 {
602 	UT_return_val_if_fail(m_pClipboard, false);
603 	const char * pszFmt = m_pClipboard->convertToFormatString(iFmt);
604 	UT_return_val_if_fail(pszFmt, false);
605 
606 	return _copyFmtToClipboard(pDocRange, pszFmt);
607 }
608 
609 /*!
610     copy data in required format to the clipboard
611 */
_copyFmtToClipboard(PD_DocumentRange * pDocRange,const char * pszFmt)612 bool AP_Win32App::_copyFmtToClipboard(PD_DocumentRange * pDocRange, const char * pszFmt)
613 {
614 	UT_return_val_if_fail(m_pClipboard && pszFmt, false);
615 
616 	UT_ByteBuf buf;
617 	UT_Error status;
618 
619 	if(0 == strcmp(AP_CLIPBOARD_TEXTPLAIN_8BIT, pszFmt))
620 	{
621 		IE_Exp_Text * pExpText = new IE_Exp_Text(pDocRange->m_pDoc);
622 		if (pExpText)
623 		{
624 			status = pExpText->copyToBuffer(pDocRange,&buf);
625 
626 			if(status != UT_OK)
627 				return false;
628 
629 			UT_Byte b = 0;
630 			buf.append(&b,1);			// NULL terminate the string
631 			m_pClipboard->addData(AP_CLIPBOARD_TEXTPLAIN_8BIT,
632 								  (UT_Byte *)buf.getPointer(0),buf.getLength());
633 			DELETEP(pExpText);
634 			UT_DEBUGMSG(("CopyToClipboard: copying %d bytes in TEXTPLAIN format.\n",
635 						 buf.getLength()));
636 		}
637 		else
638 		{
639 			return false;
640 		}
641 
642 	}
643 	else if(0 == strcmp(AP_CLIPBOARD_TEXTPLAIN_UCS2, pszFmt))
644 	{
645 		const char *szEnc = XAP_EncodingManager::get_instance()->getNativeUnicodeEncodingName();
646 		IE_Exp_Text * pExpUnicodeText = new IE_Exp_Text(pDocRange->m_pDoc,szEnc);
647 		if (pExpUnicodeText)
648 		{
649 			status = pExpUnicodeText->copyToBuffer(pDocRange,&buf);
650 
651 			if(status != UT_OK)
652 				return false;
653 
654 			UT_Byte b[2] = {0,0};
655 			buf.append(b,2);			// NULL terminate the string
656 			m_pClipboard->addData(AP_CLIPBOARD_TEXTPLAIN_UCS2,
657 								  (UT_Byte *)buf.getPointer(0),buf.getLength());
658 			DELETEP(pExpUnicodeText);
659 			UT_DEBUGMSG(("CopyToClipboard: copying %d bytes in TEXTPLAIN UNICODE format.\n",
660 						 buf.getLength()*2));
661 		}
662 		else
663 		{
664 			return false;
665 		}
666 	}
667 	else if(0 == strcmp(AP_CLIPBOARD_RTF, pszFmt))
668 	{
669 		IE_Exp_RTF * pExpRtf = new IE_Exp_RTF(pDocRange->m_pDoc);
670 		if (pExpRtf)
671 		{
672 			status = pExpRtf->copyToBuffer(pDocRange,&buf);
673 
674 			if(status != UT_OK)
675 				return false;
676 
677 			UT_Byte b = 0;
678 			buf.append(&b,1);			// NULL terminate the string
679 			m_pClipboard->addData(AP_CLIPBOARD_RTF,(UT_Byte *)buf.getPointer(0),buf.getLength());
680 			DELETEP(pExpRtf);
681 			UT_DEBUGMSG(("CopyFmtToClipboard: copying %d bytes in RTF format.\n",
682 						 buf.getLength()));
683 		}
684 		else
685 		{
686 			return false;
687 		}
688 	}
689 
690 	return true;
691 }
692 
693 /*!
694     copy data to the clipboard; this is what gets called when the user
695     presses Ctrl+C
696 */
copyToClipboard(PD_DocumentRange * pDocRange,bool)697 void AP_Win32App::copyToClipboard(PD_DocumentRange * pDocRange, bool /*bUseClipboard*/)
698 {
699 	// copy the given subset of the given document to the
700 	// system clipboard in a variety of formats.
701 	// MSFT requests that we post them in the order of
702 	// importance to us (most preserving to most lossy).
703 	//
704 	// TODO do we need to put something in .ABW format on the clipboard ??
705 
706 	AP_Win32FrameImpl * pFrameImp = static_cast<AP_Win32FrameImpl*>(getLastFocussedFrame()->getFrameImpl());
707 	UT_return_if_fail(pFrameImp);
708 
709 	if (!m_pClipboard->openClipboard(pFrameImp->getHwndDocument()))
710 		return;
711 
712 	m_pClipboard->clearClipboard(); // this also gives us the ownership
713 
714 	// Be smart: always place RTF on clipboard; the
715 	// remaining formats we will generate on demand.
716 	// most of the time it will save us creating multiple importers,
717 	// but when the user requests other than the default format, it
718 	// will be a little bit more involved
719 	// Tomas, June 28, 2003.
720 
721 #ifndef COPY_ON_DEMAND
722 	_copyFmtToClipboard(pDocRange, AP_CLIPBOARD_RTF);
723 #else
724 	// we need to both cache the present doc and put rtf version on
725 	// the clipboard, because win32 will ask for it immediately;
726 	// appart from that, the rtf exporter needs some layout info to
727 	// deal with bidi issues, which means we cannot construct the rtf
728 	// from the chached doc properly
729 	_cacheClipboardDoc(pDocRange);
730 	_copyFmtToClipboard(pDocRange, AP_CLIPBOARD_RTF);
731 #endif
732 
733 	// TODO Should use a finer-grain technique than IsWinNT()
734 	// since Win98 supports unicode clipboard.
735 	if (UT_IsWinNT())
736 	{
737 		// put raw unicode text on the clipboard
738 #ifndef COPY_ON_DEMAND
739 		_copyFmtToClipboard(pDocRange, AP_CLIPBOARD_TEXTPLAIN_UCS2);
740 #else
741 		_indicateFmtToClipboard(AP_CLIPBOARD_TEXTPLAIN_UCS2);
742 #endif
743 	}
744 	else
745 	{
746 		// put raw 8bit text on the clipboard
747 #ifndef COPY_ON_DEMAND
748 		_copyFmtToClipboard(pDocRange, AP_CLIPBOARD_TEXTPLAIN_8BIT);
749 #else
750 		_indicateFmtToClipboard(AP_CLIPBOARD_TEXTPLAIN_8BIT);
751 #endif
752 	}
753 
754 	m_pClipboard->closeClipboard();				// release clipboard lock
755 }
756 
757 //
758 //
759 //
CreateBitmapInfoStruct(HBITMAP hBmp)760 PBITMAPINFO CreateBitmapInfoStruct(HBITMAP hBmp)
761 {
762 	BITMAP 		bmp;
763 	PBITMAPINFO 	pbmi;
764 	WORD    	cClrBits;
765 
766 	// Retrieve the bitmap's color format, width, and height.
767     	if (!GetObjectW(hBmp, sizeof(BITMAP), (LPSTR)&bmp))
768 		return NULL;
769 
770 	if (bmp.bmBitsPixel==16) bmp.bmBitsPixel=24;	// 16 bit BMPs are not supported by all programs
771 
772 
773 	// Convert the color format to a count of bits.
774    	cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel);
775 
776 	if (cClrBits == 1)
777 		cClrBits = 1;
778 	else if (cClrBits <= 4)
779 		cClrBits = 4;
780 	else if (cClrBits <= 8)
781 		cClrBits = 8;
782 	else if (cClrBits <= 16)
783 		cClrBits = 16;
784 	else if (cClrBits <= 24)
785 		cClrBits = 24;
786 	else cClrBits = 32;
787 
788 	// Allocate memory for the BITMAPINFO structure. (This structure
789 	// contains a BITMAPINFOHEADER structure and an array of RGBQUAD
790 	// data structures.)
791 
792 	if (cClrBits != 24)
793 	 pbmi = (PBITMAPINFO) LocalAlloc(LPTR,
794 	            sizeof(BITMAPINFOHEADER) +
795 	            sizeof(RGBQUAD) * (1<< cClrBits));
796 
797 	// There is no RGBQUAD array for the 24-bit-per-pixel format.
798 	else
799 	 pbmi = (PBITMAPINFO) LocalAlloc(LPTR,
800 	            sizeof(BITMAPINFOHEADER));
801 
802 	// Initialize the fields in the BITMAPINFO structure.
803 
804 	pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
805 	pbmi->bmiHeader.biWidth = bmp.bmWidth;
806 	pbmi->bmiHeader.biHeight = bmp.bmHeight;
807 	pbmi->bmiHeader.biPlanes = bmp.bmPlanes;
808 	pbmi->bmiHeader.biBitCount = bmp.bmBitsPixel;
809 	if (cClrBits < 24)
810 	pbmi->bmiHeader.biClrUsed = (1<<cClrBits);
811 
812 	// If the bitmap is not compressed, set the BI_RGB flag.
813 	pbmi->bmiHeader.biCompression = BI_RGB;
814 
815 	// Compute the number of bytes in the array of color
816 	// indices and store the result in biSizeImage.
817 	// For Windows NT/2000, the width must be DWORD aligned unless
818 	// the bitmap is RLE compressed.
819 	pbmi->bmiHeader.biSizeImage = ((pbmi->bmiHeader.biWidth * cClrBits +31) & ~31) /8
820 	                          * pbmi->bmiHeader.biHeight;
821 	// Set biClrImportant to 0, indicating that all of the
822 	// device colors are important.
823 	pbmi->bmiHeader.biClrImportant = 0;
824 	return pbmi;
825 }
826 
827 //
828 //
829 //
CreateBMP(HWND,UT_ByteBuf & pBB,PBITMAPINFO pbi,HBITMAP hBMP,HDC hDC)830 void CreateBMP(HWND /*hwnd*/, UT_ByteBuf & pBB, PBITMAPINFO pbi,
831                   HBITMAP hBMP, HDC hDC)
832 {
833 	BITMAPFILEHEADER hdr;       // bitmap file-header
834 	PBITMAPINFOHEADER pbih;     // bitmap info-header
835 	LPBYTE lpBits;              // memory pointer
836 
837 	if (!hBMP) return;
838 
839 	pbih = (PBITMAPINFOHEADER) pbi;
840 	lpBits = (LPBYTE) GlobalAlloc(GMEM_FIXED, pbih->biSizeImage);
841 
842 	if (!lpBits) return;
843 
844 	// Retrieve the color table (RGBQUAD array) and the bits
845 	// (array of palette indices) from the DIB.
846 	if (!GetDIBits(hDC, hBMP, 0, (WORD) pbih->biHeight, lpBits, pbi,
847 		 DIB_RGB_COLORS))
848 	return;
849 
850 	hdr.bfType = 0x4d42;        // 0x42 = "B" 0x4d = "M"
851 	// Compute the size of the entire file.
852 	hdr.bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) +
853 			pbih->biSize + pbih->biClrUsed
854 			* sizeof(RGBQUAD) + pbih->biSizeImage);
855 	hdr.bfReserved1 = 0;
856 	hdr.bfReserved2 = 0;
857 
858 	// Compute the offset to the array of color indices.
859 	hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) +
860 	pbih->biSize + pbih->biClrUsed
861 	* sizeof (RGBQUAD);
862 
863 	pBB.truncate (0);
864 
865 	// Copy the BITMAPFILEHEADER into the .BMP file.
866 	pBB.append ((const UT_Byte *)&hdr, sizeof(BITMAPFILEHEADER));
867 	pBB.append ((const UT_Byte *)pbih, sizeof(BITMAPINFOHEADER) + pbih->biClrUsed * sizeof (RGBQUAD));
868 
869 	// Copy the array of color indices into the .BMP file.
870 	pBB.append ((const UT_Byte *)lpBits, (int) pbih->biSizeImage);
871 
872 	GlobalFree((HGLOBAL)lpBits);
873 }
874 
875 
876 
pasteFromClipboard(PD_DocumentRange * pDocRange,bool,bool bHonorFormatting)877 void AP_Win32App::pasteFromClipboard(PD_DocumentRange * pDocRange, bool /*bUseClipboard*/, bool bHonorFormatting)
878 {
879 	// paste from the system clipboard using the best-for-us format
880 	// that is present.
881 
882 	// We get a handle to the object in the requested format
883 	// and then lock it an use the system buffer -- rather
884 	// then copying it into our own.
885 	//
886 	// we jump thru a few bogus steps w/r/t the length of the
887 	// object because MSFT docs state that the length of the
888 	// object may be less than the length actually returned by
889 	// GlobalSize().
890 	//
891 	// therefore, we do a strlen() and **hope** that this is
892 	// right.  Oh, and the value returned by GlobalSize() varies
893 	// from call-to-call on the same object.... sigh.
894 	AP_Win32FrameImpl * pFrameImp = static_cast<AP_Win32FrameImpl*>(getLastFocussedFrame()->getFrameImpl());
895 	UT_return_if_fail(pFrameImp);
896 
897 	if (!m_pClipboard->openClipboard(pFrameImp->getHwndDocument())) // lock clipboard
898 		return;
899 
900 	{
901 		// TODO Paste the most detailed version unless user overrides.
902 		// TODO decide if we need to support .ABW on the clipboard.
903 		if (!((bHonorFormatting && _pasteFormatFromClipboard(pDocRange, AP_CLIPBOARD_RTF, ".rtf", false)) ||
904 			_pasteFormatFromClipboard(pDocRange, AP_CLIPBOARD_TEXTPLAIN_UCS2, ".txt", true) ||
905 			_pasteFormatFromClipboard(pDocRange, AP_CLIPBOARD_BMP, ".bmp", false) ||
906 			_pasteFormatFromClipboard(pDocRange, AP_CLIPBOARD_TEXTPLAIN_8BIT, ".txt", false)))
907 		{
908 			// TODO figure out what to do with an image and other formats....
909 			UT_DEBUGMSG(("PasteFromClipboard: TODO support this format..."));
910 		}
911 	}
912 
913 	m_pClipboard->closeClipboard();				// release clipboard lock
914 	return;
915 }
916 
_pasteFormatFromClipboard(PD_DocumentRange * pDocRange,const char * szFormat,const char * szType,bool bWide)917 bool AP_Win32App::_pasteFormatFromClipboard(PD_DocumentRange * pDocRange, const char * szFormat,
918 											const char * szType, bool bWide)
919 {
920 	HANDLE	hData;
921 	bool 	bSuccess = false;
922 
923 	if (!(hData = m_pClipboard->getHandleInFormat(szFormat)))
924 		return bSuccess;
925 
926  	// It's a bitmap
927  	if (g_ascii_strcasecmp(szFormat, AP_CLIPBOARD_BMP)==0)
928 	{
929  		HBITMAP					hBitmap;
930  		PBITMAPINFO 			bi;
931  		HWND		 			hWnd;
932  		HDC 					hdc;
933  		IE_ImpGraphic*			pIEG = NULL;
934  		FG_Graphic* 			pFG = NULL;
935  		UT_Error 				errorCode;
936  		UT_ByteBuf 				byteBuf;
937  		IEGraphicFileType		iegft = IEGFT_BMP;
938  		XAP_Frame* 				pFrame;
939  		AP_FrameData* 			pFrameData;
940  		FL_DocLayout*			pDocLy;
941  		FV_View* 				pView;
942 		UT_ByteBuf*				bBufBMP = new UT_ByteBuf;
943 
944  		hBitmap = (HBITMAP)hData;
945  		hWnd =  GetDesktopWindow();
946  		hdc = GetDC(hWnd);
947 
948  		// Create a BMP file from a BITMAP
949  		bi =  CreateBitmapInfoStruct(hBitmap);
950  		CreateBMP(hWnd, *bBufBMP, bi, hBitmap,hdc);
951 
952  		// Since we are providing the file type, there is not need to pass the bytebuff filled up
953  		errorCode = IE_ImpGraphic::constructImporter(*bBufBMP, iegft, &pIEG);
954 
955  		if(errorCode != UT_OK)
956 			return false;
957 
958  		errorCode = pIEG->importGraphic(bBufBMP, &pFG);
959 
960  		if(errorCode != UT_OK || !pFG)
961 		{
962 			DELETEP(bBufBMP);
963 			DELETEP(pIEG);
964  			return false;
965 		}
966 		// sunk in importGraphic
967 		bBufBMP = NULL;
968 
969  		// Insert graphic in the view
970  		pFrame = getLastFocussedFrame();
971  		pFrameData = (AP_FrameData*) pFrame->getFrameData();
972  		pDocLy =	pFrameData->m_pDocLayout;
973  		pView =  pDocLy->getView();
974 
975  		errorCode = pView->cmdInsertGraphic(pFG);
976 
977 		DELETEP(pIEG);
978  		//DELETEP(pFG);
979 
980  		bSuccess = true;
981  	}
982  	else
983 	{
984 		unsigned char * pData = static_cast<unsigned char *>(GlobalLock(hData));
985 		UT_DEBUGMSG(("Paste: [fmt %s %s][hdata 0x%08lx][pData 0x%08lx]\n",
986 					 szFormat, szType,  hData, pData));
987 		UT_uint32 iSize = GlobalSize(hData);
988 		UT_uint32 iStrLen = bWide
989 			? wcslen(reinterpret_cast<const wchar_t *>(pData)) * 2
990 			: strlen(reinterpret_cast<const char *>(pData));
991 		UT_uint32 iLen = UT_MIN(iSize,iStrLen);
992 
993 
994 		IE_Imp * pImp = 0;
995 		IE_Imp::constructImporter(pDocRange->m_pDoc, IE_Imp::fileTypeForSuffix(szType), &pImp, 0);
996 		if (pImp)
997 		{
998 			const char * szEncoding = 0;
999 			if (bWide)
1000 			{
1001 				szEncoding = XAP_EncodingManager::get_instance()->getUCS2LEName();
1002 			}
1003 			else
1004 			{
1005 				; // TODO Get code page using CF_LOCALE
1006 			}
1007 			pImp->pasteFromBuffer(pDocRange,pData,iLen,szEncoding);
1008 			delete pImp;
1009 		}
1010 
1011 		GlobalUnlock(hData);
1012 		bSuccess = true;
1013 	}
1014 	return bSuccess;
1015 }
1016 
canPasteFromClipboard(void)1017 bool AP_Win32App::canPasteFromClipboard(void)
1018 {
1019 	if (!getLastFocussedFrame())
1020 		return false;
1021 
1022 	AP_Win32FrameImpl * pFrameImp = static_cast<AP_Win32FrameImpl*>(getLastFocussedFrame()->getFrameImpl());
1023 	UT_return_val_if_fail(pFrameImp, false);
1024 
1025 	if (!m_pClipboard->openClipboard(pFrameImp->getHwndDocument()))
1026 		return false;
1027 
1028 	// TODO decide if we need to support .ABW format on the clipboard.
1029 	if (m_pClipboard->hasFormat(AP_CLIPBOARD_RTF))
1030 		goto ReturnTrue;
1031 	if (m_pClipboard->hasFormat(AP_CLIPBOARD_TEXTPLAIN_UCS2))
1032 		goto ReturnTrue;
1033 	if (m_pClipboard->hasFormat(AP_CLIPBOARD_TEXTPLAIN_8BIT))
1034 		goto ReturnTrue;
1035 
1036 	// If IEGFT_BMP!=0 we have a plugin that can deal with BMP format
1037 	if (m_pClipboard->hasFormat(AP_CLIPBOARD_BMP) && IEGFT_BMP)
1038   		goto ReturnTrue;
1039 
1040 	m_pClipboard->closeClipboard();
1041 	return false;
1042 
1043 ReturnTrue:
1044 	m_pClipboard->closeClipboard();
1045 	return true;
1046 }
1047 
1048 /*****************************************************************/
1049 
1050 #if defined(_DEBUG) && defined(_MSC_VER)
1051 #define  SET_CRT_DEBUG_FIELD(a) \
1052             _CrtSetDbgFlag((a) | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
1053 #define  CLEAR_CRT_DEBUG_FIELD(a) \
1054             _CrtSetDbgFlag(~(a) & _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
1055 #else
1056 #define  SET_CRT_DEBUG_FIELD(a)   ((void) 0)
1057 #define  CLEAR_CRT_DEBUG_FIELD(a) ((void) 0)
1058 #endif
1059 
1060 /*****************************************************************/
1061 
WinMain(const char * szAppName,HINSTANCE hInstance,HINSTANCE,PSTR,int iCmdShow)1062 int AP_Win32App::WinMain(const char * szAppName, HINSTANCE hInstance,
1063 						 HINSTANCE /*hPrevInstance*/, PSTR /*szCmdLine*/, int iCmdShow)
1064 {
1065 #if !GLIB_CHECK_VERSION(2,32,0)
1066 	if (!g_thread_supported ())
1067 		g_thread_init (NULL);
1068 #endif
1069 
1070 	bool bShowApp = true;
1071 	BOOL bInitialized = FALSE;
1072 
1073 	// this is a static function and doesn't have a 'this' pointer.
1074 	MSG msg;
1075 
1076 #ifdef _MSC_VER
1077 	_CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_DEBUG );
1078 	_CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_DEBUG );
1079 	_CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_WNDW);
1080 #endif
1081 
1082 	// HACK: load least-common-denominator Rich Edit control
1083 	// TODO: fix Spell dlg so we don't rely on this
1084 	// ALT:  make it a Preview widget instead
1085 
1086 	HINSTANCE hinstRich = LoadLibraryW(L"riched32.dll");
1087 	if (!hinstRich)
1088 		hinstRich = LoadLibraryW(L"riched20.dll");
1089 	UT_return_val_if_fail (hinstRich, 1);
1090 
1091 	AP_Win32App * pMyWin32App;
1092 
1093 	// OLE Stuff
1094 	if (SUCCEEDED(OleInitialize(NULL)))
1095             bInitialized = TRUE;
1096 
1097 
1098 // We put this in a block to force the destruction of Args in the stack
1099 {
1100 	UT_Win32LocaleString scnv;
1101 	UT_UTF8String sUTFCmdLine;
1102 
1103 	// Load the command line into an XAP_Args class
1104 	scnv.fromLocale(GetCommandLineW());
1105 	sUTFCmdLine=scnv.utf8_str();
1106 	XAP_Args XArgs = XAP_Args(sUTFCmdLine.utf8_str());
1107 
1108 	// Step 1: Initialize our application.
1109 	pMyWin32App = new AP_Win32App(hInstance, szAppName);
1110 	AP_Args Args = AP_Args(&XArgs, szAppName, pMyWin32App);
1111 
1112 	Args.parseOptions();
1113 	pMyWin32App->initialize();
1114 
1115 	// Step 2: Handle all non-window args.
1116 	// process args (calls common arg handler, which then calls platform specific)
1117 	// As best I understand, it returns true to continue and show window, or
1118 	// false if no window should be shown (and thus we should simply exit).
1119 	bool windowlessArgsWereSuccessful = true;
1120 	if (!Args.doWindowlessArgs(windowlessArgsWereSuccessful))
1121 	{
1122 		pMyWin32App->shutdown();	// properly shutdown the app 1st
1123 		delete pMyWin32App;
1124 		return (windowlessArgsWereSuccessful ? 0 : -1);
1125 	}
1126 
1127 	// Step 3: Create windows as appropriate.
1128 	// if some args are botched, it returns false and we should
1129 	// continue out the door.
1130 	// We used to check for bShowApp here.  It shouldn't be needed
1131 	// anymore, because doWindowlessArgs was supposed to bail already. -PL
1132 	if (!pMyWin32App->openCmdLineFiles(&Args))
1133 	{
1134 		pMyWin32App->shutdown();	// properly shutdown the app 1st
1135 		delete pMyWin32App;
1136 		return 0;
1137 	}
1138 }
1139 //
1140 // This block is controlled by the Structured Exception Handle
1141 // if any crash happens here we will recover it and save the file (cross fingers)
1142 //
1143 
1144 
1145 try
1146 {
1147 	UT_uint32 iHeight = 0, iWidth = 0, t_flag =0;
1148 	UT_sint32 iPosX = 0, iPosY = 0;
1149 
1150 	if (!((XAP_App::getApp()->getGeometry(&iPosX,&iPosY,&iWidth,&iHeight,&t_flag)) &&
1151 	       ((iWidth > 0) && (iHeight > 0)))	)
1152 		XAP_App::getApp()->getDefaultGeometry(iWidth,iHeight,t_flag);
1153 
1154 	if ((t_flag & PREF_FLAG_GEOMETRY_MAXIMIZED)==PREF_FLAG_GEOMETRY_MAXIMIZED)
1155 			iCmdShow = SW_SHOWMAXIMIZED;
1156 
1157 	if (bShowApp)
1158 	{
1159 		// display the windows
1160 		for(UT_sint32 i = 0; i < pMyWin32App->m_vecFrames.getItemCount(); i++)
1161 		{
1162 			AP_Win32Frame * curFrame = (AP_Win32Frame*)pMyWin32App->m_vecFrames[i];
1163 			UT_continue_if_fail(curFrame);
1164 
1165 			HWND hwnd = curFrame->getTopLevelWindow();
1166 			ShowWindow(hwnd, iCmdShow);
1167 			UpdateWindow(hwnd);
1168 		}
1169 
1170 		// do dispatch loop
1171 		while(UT_GetMessage(&msg, NULL, 0, 0))
1172 	    {
1173    	      	// TranslateMessage is not called because AbiWord
1174 	      	// has its own way of decoding keyboard accelerators
1175 	      	if (pMyWin32App->handleModelessDialogMessage(&msg))
1176 				continue;
1177 
1178 			TranslateMessage(&msg);
1179 			UT_DispatchMessage(&msg);
1180 
1181 			// Check for idle condition
1182 			while( !UT_Win32Idle::_isEmpty() &&
1183                    !PeekMessageW(&msg, NULL, 0, 0, PM_NOREMOVE) )
1184 			{
1185 				// Fire idle functions when no pending messages
1186 		    	UT_Win32Idle::_fireall();
1187 			}
1188 	    }
1189 	}
1190 
1191 	// Un-init OLE
1192         if (bInitialized)
1193                 OleUninitialize();
1194 
1195 	FreeLibrary(hinstRich);
1196 
1197 	// unload all loaded plugins (remove some of the memory leaks shown at shutdown :-)
1198 	XAP_ModuleManager::instance().unloadAllPlugins();
1199 
1200 	// Step 4: Destroy the App.  It should take care of deleting all frames.
1201 	pMyWin32App->shutdown();
1202 	delete pMyWin32App;
1203 
1204 
1205 }// end of thes block is controlled by the Exception Handler
1206 
1207 //
1208 // If an exception happens, with "catch" the block
1209 // and then the save it into disk
1210 //
1211 catch (...)
1212 {
1213 #ifdef DEBUG
1214 	throw;
1215 #endif
1216 
1217 	AP_Win32App *pApp = (AP_Win32App *) XAP_App::getApp();
1218 
1219 	UT_return_val_if_fail (pApp,1);
1220 
1221 	// first of all, try to save the current prefs (so that any log entries are dumped
1222 	// onto disk -- this allows us to save useful info for dbg purposes) we will enclose
1223 	// this inside of a try/catch block, so that in the (unlikely) case something goes
1224 	// badly wrong when writing the prefs file, we still get chance to save the open
1225 	// documents
1226 
1227 	try
1228 	{
1229 		if(pApp->getPrefs())
1230 		{
1231 			pApp->getPrefs()->savePrefsFile();
1232 		}
1233 	}
1234 	catch(...)
1235 	{
1236 		// do nothing
1237 	}
1238 
1239 	IEFileType abiType = IE_Imp::fileTypeForSuffix(".abw");
1240 	for (UT_sint32 i = 0; i < pApp->m_vecFrames.getItemCount(); i++)
1241 	{
1242 		AP_Win32Frame * curFrame = (AP_Win32Frame*)pApp->m_vecFrames[i];
1243 		UT_continue_if_fail(curFrame);
1244 
1245 		// again, we want to catch any exception thrown while saving individual documents,
1246 		// in order to run through the whole loop
1247 		try
1248 		{
1249 			if (NULL == curFrame->getFilename())
1250 				curFrame->backup(".abw.saved", abiType);
1251 			else
1252 				curFrame->backup(".saved", abiType);
1253 		}
1254 		catch(...)
1255 		{
1256 			// do nothing
1257 		}
1258 	}
1259 
1260 	// Tell the user was has just happened
1261 	AP_Win32Frame * curFrame = (AP_Win32Frame*)pApp->m_vecFrames[0];
1262 	if (curFrame)
1263 	{
1264 		curFrame->showMessageBox(AP_STRING_ID_MSG_Exception,XAP_Dialog_MessageBox::b_O, XAP_Dialog_MessageBox::a_OK);
1265 
1266 	}
1267 }// end of except
1268 
1269 	SET_CRT_DEBUG_FIELD( _CRTDBG_LEAK_CHECK_DF );
1270 	return msg.wParam;
1271 }
1272 
1273 /* This function takes a description and compares it all the registerd
1274    importers descriptions and returns either the appropriate importer's
1275    IEFileType or returns IEFT_Unknown if no match was made.
1276 */
_getFileTypeFromDesc(const char * desc)1277 IEFileType AP_Win32App::_getFileTypeFromDesc(const char *desc)
1278 {
1279 	const char *iftDesc;
1280 	const char *iftSuffixList;
1281 	IEFileType ift;
1282 
1283 	// no description given or description == 'UNKNOWN' then unknown
1284 	if (!desc || !*desc || (g_ascii_strcasecmp(desc, "Unknown")==0))
1285 		return IEFT_Unknown;
1286 
1287 	UT_uint32 i = 0;
1288 	while (IE_Imp::enumerateDlgLabels(i, &iftDesc, &iftSuffixList, &ift))
1289 	{
1290 		// TODO: change to actually test all but suffixes,
1291 		// ie if iftDesc == 'Some FileType (*.sft, *.someft)' then only
1292             // test against 'Some FileType'
1293 		if (g_ascii_strncasecmp(iftDesc, desc, strlen(desc)) == 0)
1294 			return ift;
1295 
1296 		// try next importer
1297 		i++;
1298 	}
1299 
1300 	// if we made it here then description didn't match anything, so unknown.
1301 	return IEFT_Unknown;
1302 }
1303 
fileOpen(XAP_Frame * pFrame,const char * pNewFile)1304 UT_Error AP_Win32App::fileOpen(XAP_Frame * pFrame, const char * pNewFile)
1305 {
1306 	return ::fileOpen(pFrame, pNewFile, IEFT_Unknown);
1307 }
1308 
handleModelessDialogMessage(MSG * msg)1309 bool AP_Win32App::handleModelessDialogMessage( MSG * msg )
1310 {
1311 	int iCounter;
1312 	HWND hWnd = NULL;
1313 
1314 	// Try to knock off the easy case quickly
1315 	if( m_IdTable[ 0 ].id == -1 )
1316 		return false;
1317 
1318     for( iCounter = 0; iCounter <= NUM_MODELESSID; iCounter++ )
1319 	{
1320 		if( m_IdTable[ iCounter ].id != -1 )
1321 		{
1322 			hWnd = (HWND) m_IdTable[ iCounter ].pDialog->pGetWindowHandle();
1323 
1324 			if( hWnd && IsDialogMessageW( hWnd, msg ) )
1325 				return true;
1326 		}
1327 		else
1328 			break;
1329 	}
1330 
1331 	return false;
1332 }
1333 
1334 // cmdline processing call back I reckon
errorMsgBadArg(const char * msg)1335 void AP_Win32App::errorMsgBadArg(const char *msg)
1336 {
1337 	char *pszMessage;
1338 	UT_Win32LocaleString str;
1339 
1340 	pszMessage = g_strdup_printf ("%s\nRun with --help' to see a full list of available command line options.\n", msg);
1341 	str.fromUTF8(pszMessage);
1342 	MessageBoxW(NULL, str.c_str(), L"Command Line Option Error", MB_OK|MB_ICONERROR);
1343 	g_free( pszMessage );
1344 }
1345 
1346 // cmdline processing call back I reckon
errorMsgBadFile(XAP_Frame * pFrame,const char * file,UT_Error error)1347 void AP_Win32App::errorMsgBadFile(XAP_Frame * pFrame, const char * file,
1348 							 UT_Error error)
1349 {
1350 	s_CouldNotLoadFileMessage (pFrame, file, error);
1351 }
1352 
1353 /*!
1354  * A callback for AP_Args's doWindowlessArgs call which handles
1355  * platform-specific windowless args.
1356  * return false if we should exit normally but Window should not be displayed
1357  */
doWindowlessArgs(const AP_Args * Args,bool & bSuccess)1358 bool AP_Win32App::doWindowlessArgs(const AP_Args *Args, bool & bSuccess)
1359 {
1360 	bSuccess = true;
1361 
1362 	AP_Win32App * pMyWin32App = static_cast<AP_Win32App*>(Args->getApp());
1363 
1364 	if (Args->m_sGeometry)
1365 	{
1366 		// [--geometry <X geometry string>]
1367 		#if 0
1368 		gint x = 0;
1369 		gint y = 0;
1370 		guint width = 0;
1371 		guint height = 0;
1372 
1373 		XParseGeometry(Args->m_sGeometry, &x, &y, &width, &height);
1374 
1375 		// set the xap-level geometry for future frame use
1376 		Args->getApp()->setGeometry(x, y, width, height, f);
1377 		#endif
1378 
1379 		parseAndSetGeometry(Args->m_sGeometry);
1380 	}
1381 	else
1382 	if (Args->m_sPrintTo)
1383 	{
1384 		if (Args->m_sFiles[0])
1385 		{
1386 			UT_DEBUGMSG(("DOM: Printing file %s\n", Args->m_sFiles[0]));
1387 			AP_Convert conv ;
1388 
1389 			if (Args->m_sMerge)
1390 				conv.setMergeSource (Args->m_sMerge);
1391 
1392 			if (Args->m_impProps)
1393 				conv.setImpProps (Args->m_impProps);
1394 			if (Args->m_expProps)
1395 				conv.setExpProps (Args->m_expProps);
1396 
1397 			UT_String s = "AbiWord: ";
1398 			s+= Args->m_sFiles[0];
1399 
1400             UT_Win32LocaleString prn, doc;
1401 			prn.fromASCII (Args->m_sPrintTo);
1402 			doc.fromASCII (s.c_str());
1403 			GR_Graphics * pG = GR_Win32Graphics::getPrinterGraphics(prn.c_str(), doc.c_str());
1404             if(!pG)
1405 			{
1406 				// do not assert here, if the graphics creation failed, the static
1407 				// constructor has asserted already somewhere more relevant
1408 				return false;
1409 			}
1410 
1411 			conv.setVerbose(Args->m_iVerbose);
1412 			conv.print (Args->m_sFiles[0], pG, Args->m_sFileExtension);
1413 
1414 			delete pG;
1415 		}
1416 		else
1417 		{
1418 			// couldn't load document
1419 			UT_DEBUGMSG(("Error: no file to print!\n"));
1420 			bSuccess = false;
1421 		}
1422 
1423 		return false;
1424 	}
1425 
1426 	if(Args->m_sPluginArgs)
1427 	{
1428 	//
1429 	// Start a plugin rather than the main abiword application.
1430 	//
1431 	    const char * szName = NULL;
1432 		XAP_Module * pModule = NULL;
1433 		bool bFound = false;
1434 		if(Args->m_sPluginArgs[0])
1435 		{
1436 			const char * szRequest = Args->m_sPluginArgs[0];
1437 			const UT_GenericVector<XAP_Module*> * pVec = XAP_ModuleManager::instance().enumModules ();
1438 			UT_DEBUGMSG((" %d plugins loaded \n",pVec->getItemCount()));
1439 			for (UT_sint32 i = 0; (i < pVec->size()) && !bFound; i++)
1440 			{
1441 				pModule = pVec->getNthItem (i);
1442 				szName = pModule->getModuleInfo()->name;
1443 				UT_DEBUGMSG(("%s\n", szName));
1444 				if(strcmp(szName,szRequest) == 0)
1445 				{
1446 					bFound = true;
1447 				}
1448 			}
1449 		}
1450 		if(!bFound)
1451 		{
1452 			UT_DEBUGMSG(("Plugin %s not found or loaded \n",Args->m_sPluginArgs[0]));
1453 			bSuccess = false;
1454 			return false;
1455 		}
1456 
1457 //
1458 // You must put the name of the ev_EditMethod in the usage field
1459 // of the plugin registered information.
1460 //
1461 		const char * evExecute = pModule->getModuleInfo()->usage;
1462 		EV_EditMethodContainer* pEMC = pMyWin32App->getEditMethodContainer();
1463 		const EV_EditMethod * pInvoke = pEMC->findEditMethodByName(evExecute);
1464 		if(!pInvoke)
1465 		{
1466 			UT_DEBUGMSG(("Plugin %s invoke method %s not found \n",
1467 				   Args->m_sPluginArgs[0],evExecute));
1468 			bSuccess = false;
1469 			return false;
1470 		}
1471 		//
1472 		// Execute the plugin, then quit
1473 		//
1474 		ev_EditMethod_invoke(pInvoke, UT_String("Called From App"));
1475 		return false;
1476 	}
1477 
1478 	return true;
1479 }
1480 
1481 
1482 /*
1483 	Get the user interface languages installed
1484 	Caller should delete the allocated vector
1485 */
getInstalledUILanguages(void)1486 UT_Vector*	AP_Win32App::getInstalledUILanguages(void)
1487 {
1488 	UT_Vector* pVec = new UT_Vector(64,16);
1489 	UT_Language lang;
1490 
1491 	for (UT_uint32 i=0; i< lang.getCount(); i++)
1492 	{
1493 		const char *pLangCode = (const char*)lang.getNthLangCode(i);
1494 		if (doesStringSetExist(pLangCode))
1495 			pVec->addItem(g_strdup((char*)pLangCode));
1496 		else
1497 		{
1498 			/*The en-US is the default internal string set and wont be found on disk but it should be also listed*/
1499 			if (strcmp(pLangCode, "en-US")==0)
1500 				pVec->addItem(g_strdup((char*)pLangCode));
1501 		}
1502 
1503 	}
1504 
1505 	return pVec;
1506 }
1507 
1508 /*
1509 	Does a stringSet exist on disk?
1510 */
doesStringSetExist(const char * pLocale)1511 bool	AP_Win32App::doesStringSetExist(const char* pLocale)
1512 {
1513 	HANDLE in;
1514 	const char * szDirectory = NULL;
1515 
1516 	UT_return_val_if_fail(pLocale, false);
1517 
1518 	getPrefsValueDirectory(true,AP_PREF_KEY_StringSetDirectory,&szDirectory);
1519 	UT_return_val_if_fail(((szDirectory) && (*szDirectory)), false);
1520 
1521 	char *szPathname = (char*) UT_calloc(sizeof(char),strlen(szDirectory)+strlen(pLocale)+100);
1522 	UT_return_val_if_fail(szPathname, false);
1523 
1524 	char *szDest = szPathname;
1525 	strcpy(szDest, szDirectory);
1526 	szDest += strlen(szDest);
1527 	if ((szDest > szPathname) && (szDest[-1]!='\\'))
1528 		*szDest++='\\';
1529 	lstrcpyA(szDest,pLocale);
1530 	lstrcatA(szDest,".strings");
1531 
1532 	UT_Win32LocaleString wsFilename;
1533 	wsFilename.fromUTF8(szPathname);
1534 
1535 	in = CreateFileW(wsFilename.c_str(),0,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,
1536 		OPEN_EXISTING,0,NULL);
1537 	g_free (szPathname);
1538 
1539 	if (in!=INVALID_HANDLE_VALUE)
1540 	{
1541 		CloseHandle(in);
1542 		return true;
1543 	}
1544 
1545 	return false;
1546 }
1547 
1548 
1549 /* From UCS4 To WinLocale */
s_fromUCS4ToWinLocale(const UT_UCS4Char * szIn)1550 UT_Win32LocaleString	AP_Win32App::s_fromUCS4ToWinLocale(const UT_UCS4Char * szIn)
1551 {
1552 	UT_Win32LocaleString sRslt;
1553 	sRslt.fromUCS4(szIn);
1554 	//UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
1555 	return sRslt;
1556 }
1557 
1558 /* From WinLocale To UCS4*/
s_fromWinLocaleToUCS4(const char * szIn)1559 UT_UCS4String	AP_Win32App::s_fromWinLocaleToUCS4(const char* szIn)
1560 {
1561 	UT_UCS4Char * src = new UT_UCS4Char[strlen(szIn)+1];
1562 	UT_UCS4_strcpy_char(src, (char*)szIn);
1563 	UT_UCS4String sRslt(src);
1564 	delete [] src;
1565 
1566 	return sRslt;
1567 }
1568 
1569 /* From  UTF8 To WinLocale */
s_fromUTF8ToWinLocale(const char * szInUTF8)1570 UT_Win32LocaleString 	AP_Win32App::s_fromUTF8ToWinLocale(const char* szInUTF8)
1571 {
1572 	UT_UTF8String utf8(szInUTF8);
1573 	UT_UCS4String sUCS4(utf8.ucs4_str());
1574 	return AP_Win32App::s_fromUCS4ToWinLocale(sUCS4.ucs4_str());
1575 }
1576 
1577 /* From WinLocale To UTF8*/
s_fromWinLocaleToUTF8(const char * szIn)1578 UT_UTF8String	AP_Win32App::s_fromWinLocaleToUTF8(const char* szIn)
1579 {
1580 	UT_UCS4String sUCS4 = AP_Win32App::s_fromWinLocaleToUCS4(szIn);
1581 	UT_UTF8String sRslt(sUCS4.utf8_str());
1582 
1583 	return sRslt;
1584 }
1585 
newDefaultScreenGraphics() const1586 GR_Graphics * AP_Win32App::newDefaultScreenGraphics() const
1587 {
1588 	XAP_Frame * pFrame = findValidFrame();
1589 	UT_return_val_if_fail( pFrame, NULL );
1590 
1591 	AP_Win32FrameImpl * pFI = (AP_Win32FrameImpl *) pFrame->getFrameImpl();
1592 	UT_return_val_if_fail( pFI, NULL );
1593 
1594 	return pFI->createDocWndGraphics();
1595 }
1596