1 /**
2 * Implementation of the file dialog interfaces defined in filedialog.h for Win32
3 *
4 * Authors:
5 * Joel Holdsworth
6 * The Inkscape Organization
7 *
8 * Copyright (C) 2004-2008 The Inkscape Organization
9 *
10 * Released under GNU GPL, read the file 'COPYING' for more information
11 */
13 #ifdef HAVE_CONFIG_H
14 # include <config.h>
15 #endif
17 #ifdef WIN32
19 //General includes
20 #include <list>
21 #include <unistd.h>
22 #include <sys/stat.h>
23 #include <errno.h>
24 #include <set>
25 #include <gdk/gdkwin32.h>
26 #include <glib/gstdio.h>
27 #include <glibmm/i18n.h>
28 #include <gtkmm/window.h>
30 //Inkscape includes
31 #include "inkscape.h"
32 #include "prefs-utils.h"
33 #include <dialogs/dialog-events.h>
34 #include <extension/input.h>
35 #include <extension/output.h>
36 #include <extension/db.h>
38 #include <libnr/nr-pixops.h>
39 #include <libnr/nr-translate-scale-ops.h>
40 #include <display/nr-arena-item.h>
41 #include <display/nr-arena.h>
42 #include "sp-item.h"
43 #include "canvas-arena.h"
45 #include "filedialog.h"
46 #include "filedialogimpl-win32.h"
48 #include <zlib.h>
49 #include <cairomm/win32_surface.h>
50 #include <cairomm/context.h>
52 using namespace std;
53 using namespace Glib;
54 using namespace Cairo;
55 using namespace Gdk::Cairo;
57 namespace Inkscape
58 {
59 namespace UI
60 {
61 namespace Dialog
62 {
64 const int PreviewWidening = 150;
65 const char PreviewWindowClassName[] = "PreviewWnd";
66 const unsigned long MaxPreviewFileSize = 1344; // kB
68 #define IDC_SHOW_PREVIEW 1000
70 // Windows 2000 version of OPENFILENAMEW
71 struct OPENFILENAMEEXW : public OPENFILENAMEW {
72 void * pvReserved;
73 DWORD dwReserved;
74 DWORD FlagsEx;
75 };
77 struct Filter
78 {
79 gunichar2* name;
80 glong name_length;
81 gunichar2* filter;
82 glong filter_length;
83 Inkscape::Extension::Extension* mod;
84 };
86 ustring utf16_to_ustring(const wchar_t *utf16string, int utf16length = -1)
87 {
88 gchar *utf8string = g_utf16_to_utf8((const gunichar2*)utf16string,
89 utf16length, NULL, NULL, NULL);
90 ustring result(utf8string);
91 g_free(utf8string);
93 return result;
94 }
96 /*#########################################################################
97 ### F I L E D I A L O G B A S E C L A S S
98 #########################################################################*/
100 FileDialogBaseWin32::FileDialogBaseWin32(Gtk::Window &parent,
101 const Glib::ustring &dir, const gchar *title,
102 FileDialogType type, gchar const* /*preferenceBase*/) :
103 dialogType(type),
104 parent(parent),
105 _current_directory(dir)
106 {
107 //_mutex = NULL;
108 _main_loop = NULL;
110 _title = (wchar_t*)g_utf8_to_utf16(title, -1, NULL, NULL, NULL);
112 Glib::RefPtr<const Gdk::Window> parentWindow = parent.get_window();
113 g_assert(parentWindow->gobj() != NULL);
114 _ownerHwnd = (HWND)gdk_win32_drawable_get_handle((GdkDrawable*)parentWindow->gobj());
115 }
117 FileDialogBaseWin32::~FileDialogBaseWin32()
118 {
119 g_free(_title);
120 }
122 Inkscape::Extension::Extension *FileDialogBaseWin32::getSelectionType()
123 {
124 return _extension;
125 }
127 Glib::ustring FileDialogBaseWin32::getCurrentDirectory()
128 {
129 return _current_directory;
130 }
132 /*#########################################################################
133 ### F I L E O P E N
134 #########################################################################*/
136 bool FileOpenDialogImplWin32::_show_preview = true;
138 /**
139 * Constructor. Not called directly. Use the factory.
140 */
141 FileOpenDialogImplWin32::FileOpenDialogImplWin32(Gtk::Window &parent,
142 const Glib::ustring &dir,
143 FileDialogType fileTypes,
144 const gchar *title) :
145 FileDialogBaseWin32(parent, dir, title, fileTypes, "dialogs.open")
146 {
147 // Initalize to Autodetect
148 _extension = NULL;
150 // Set our dialog type (open, import, etc...)
151 dialogType = fileTypes;
153 _show_preview_button_bitmap = NULL;
154 _preview_wnd = NULL;
155 _file_dialog_wnd = NULL;
156 _base_window_proc = NULL;
158 _preview_file_size = 0;
159 _preview_bitmap = NULL;
160 _preview_file_icon = NULL;
161 _preview_document_width = 0;
162 _preview_document_height = 0;
163 _preview_image_width = 0;
164 _preview_image_height = 0;
166 createFilterMenu();
167 }
170 /**
171 * Destructor
172 */
173 FileOpenDialogImplWin32::~FileOpenDialogImplWin32()
174 {
175 if(_filter != NULL)
176 delete[] _filter;
177 if(_extension_map != NULL)
178 delete[] _extension_map;
179 }
181 void FileOpenDialogImplWin32::createFilterMenu()
182 {
183 list<Filter> filter_list;
185 // Compose the filter string
186 Inkscape::Extension::DB::InputList extension_list;
187 Inkscape::Extension::db.get_input_list(extension_list);
189 ustring all_inkscape_files_filter, all_image_files_filter;
190 Filter all_files, all_inkscape_files, all_image_files;
192 const gchar *all_files_filter_name = _("All Files");
193 const gchar *all_inkscape_files_filter_name = ("All Inkscape Files");
194 const gchar *all_image_files_filter_name = _("All Image Files");
196 // Calculate the amount of memory required
197 int filter_count = 3; // 3 - one for All Files, All Images and All Inkscape Files
198 int filter_length = 1;
200 for (Inkscape::Extension::DB::InputList::iterator current_item = extension_list.begin();
201 current_item != extension_list.end(); current_item++)
202 {
203 Filter filter;
205 Inkscape::Extension::Input *imod = *current_item;
206 if (imod->deactivated()) continue;
208 // Type
209 filter.name = g_utf8_to_utf16(imod->get_filetypename(),
210 -1, NULL, &filter.name_length, NULL);
212 // Extension
213 const gchar *file_extension_name = imod->get_extension();
214 filter.filter = g_utf8_to_utf16(file_extension_name,
215 -1, NULL, &filter.filter_length, NULL);
217 filter.mod = imod;
218 filter_list.push_back(filter);
220 filter_length += filter.name_length +
221 filter.filter_length + 3; // Add 3 for two \0s and a *
223 // Add to the "All Inkscape Files" Entry
224 if(all_inkscape_files_filter.length() > 0)
225 all_inkscape_files_filter += ";*";
226 all_inkscape_files_filter += file_extension_name;
227 if( strncmp("image", imod->get_mimetype(), 5) == 0)
228 {
229 // Add to the "All Image Files" Entry
230 if(all_image_files_filter.length() > 0)
231 all_image_files_filter += ";*";
232 all_image_files_filter += file_extension_name;
233 }
235 filter_count++;
236 }
238 int extension_index = 0;
239 _extension_map = new Inkscape::Extension::Extension*[filter_count];
241 // Filter Image Files
242 all_image_files.name = g_utf8_to_utf16(all_image_files_filter_name,
243 -1, NULL, &all_image_files.name_length, NULL);
244 all_image_files.filter = g_utf8_to_utf16(all_image_files_filter.data(),
245 -1, NULL, &all_image_files.filter_length, NULL);
246 filter_list.push_front(all_image_files);
247 _extension_map[extension_index++] = NULL;
249 // Filter Inkscape Files
250 all_inkscape_files.name = g_utf8_to_utf16(all_inkscape_files_filter_name,
251 -1, NULL, &all_inkscape_files.name_length, NULL);
252 all_inkscape_files.filter = g_utf8_to_utf16(all_inkscape_files_filter.data(),
253 -1, NULL, &all_inkscape_files.filter_length, NULL);
254 filter_list.push_front(all_inkscape_files);
255 _extension_map[extension_index++] = NULL;
257 // Filter All Files
258 all_files.name = g_utf8_to_utf16(all_files_filter_name,
259 -1, NULL, &all_files.name_length, NULL);
260 all_files.filter = NULL;
261 all_files.filter_length = 0;
262 filter_list.push_front(all_files);
263 _extension_map[extension_index++] = NULL;
265 filter_length += all_files.name_length + 3 +
266 all_inkscape_files.filter_length +
267 all_inkscape_files.name_length + 3 +
268 all_image_files.filter_length +
269 all_image_files.name_length + 3 + 1;
270 // Add 3 for 2*2 \0s and a *, and 1 for a trailing \0
273 _filter = new wchar_t[filter_length];
274 wchar_t *filterptr = _filter;
276 for(list<Filter>::iterator filter_iterator = filter_list.begin();
277 filter_iterator != filter_list.end(); filter_iterator++)
278 {
279 const Filter &filter = *filter_iterator;
281 memcpy(filterptr, filter.name, filter.name_length * 2);
282 filterptr += filter.name_length;
283 g_free(filter.name);
285 *(filterptr++) = L'\0';
286 *(filterptr++) = L'*';
288 if(filter.filter != NULL)
289 {
290 memcpy(filterptr, filter.filter, filter.filter_length * 2);
291 filterptr += filter.filter_length;
292 g_free(filter.filter);
293 }
295 *(filterptr++) = L'\0';
297 // Associate this input extension with the file type name
298 _extension_map[extension_index++] = filter.mod;
299 }
300 *(filterptr++) = L'\0';
302 _filterIndex = 2;
303 }
305 void FileOpenDialogImplWin32::GetOpenFileName_thread()
306 {
307 OPENFILENAMEEXW ofn;
309 g_assert(this != NULL);
310 //g_assert(_mutex != NULL);
311 g_assert(_main_loop != NULL);
313 WCHAR* current_directory_string = (WCHAR*)g_utf8_to_utf16(
314 _current_directory.data(), -1, NULL, NULL, NULL);
316 memset(&ofn, 0, sizeof(ofn));
318 // Copy the selected file name, converting from UTF-8 to UTF-16
319 memset(_path_string, 0, sizeof(_path_string));
320 gunichar2* utf16_path_string = g_utf8_to_utf16(
321 myFilename.data(), -1, NULL, NULL, NULL);
322 wcsncpy(_path_string, (wchar_t*)utf16_path_string, _MAX_PATH);
323 g_free(utf16_path_string);
325 ofn.lStructSize = sizeof(ofn);
326 ofn.hwndOwner = _ownerHwnd;
327 ofn.lpstrFile = _path_string;
328 ofn.nMaxFile = _MAX_PATH;
329 ofn.lpstrFileTitle = NULL;
330 ofn.nMaxFileTitle = 0;
331 ofn.lpstrInitialDir = current_directory_string;
332 ofn.lpstrTitle = _title;
333 ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_EXPLORER | OFN_ENABLEHOOK | OFN_HIDEREADONLY | OFN_ENABLESIZING;
334 ofn.lpstrFilter = _filter;
335 ofn.nFilterIndex = _filterIndex;
336 ofn.lpfnHook = GetOpenFileName_hookproc;
337 ofn.lCustData = (LPARAM)this;
339 _result = GetOpenFileNameW(&ofn) != 0;
341 _filterIndex = ofn.nFilterIndex;
342 _extension = _extension_map[ofn.nFilterIndex];
344 myFilename = utf16_to_ustring(_path_string, _MAX_PATH);
346 // Copy the selected file name, converting from UTF-16 to UTF-8
347 myFilename = utf16_to_ustring(_path_string, _MAX_PATH);
349 // Tidy up
350 g_free(current_directory_string);
352 _mutex->lock();
353 _finished = true;
354 _mutex->unlock();
355 //g_main_loop_quit(_main_loop);
358 }
360 void FileOpenDialogImplWin32::register_preview_wnd_class()
361 {
362 HINSTANCE hInstance = GetModuleHandle(NULL);
363 const WNDCLASSA PreviewWndClass =
364 {
365 CS_HREDRAW | CS_VREDRAW,
366 preview_wnd_proc,
367 0,
368 0,
369 hInstance,
370 NULL,
371 LoadCursor(hInstance, IDC_ARROW),
372 (HBRUSH)(COLOR_BTNFACE + 1),
373 NULL,
374 PreviewWindowClassName
375 };
377 RegisterClassA(&PreviewWndClass);
378 }
380 UINT_PTR CALLBACK FileOpenDialogImplWin32::GetOpenFileName_hookproc(
381 HWND hdlg, UINT uiMsg, WPARAM, LPARAM lParam)
382 {
383 FileOpenDialogImplWin32 *pImpl = (FileOpenDialogImplWin32*)
384 GetWindowLongPtr(hdlg, GWLP_USERDATA);
386 switch(uiMsg)
387 {
388 case WM_INITDIALOG:
389 {
390 HWND hParentWnd = GetParent(hdlg);
391 HINSTANCE hInstance = GetModuleHandle(NULL);
393 // Make the window a bit wider
394 RECT rcRect;
395 GetWindowRect(hParentWnd, &rcRect);
396 MoveWindow(hParentWnd, rcRect.left, rcRect.top,
397 rcRect.right - rcRect.left + PreviewWidening,
398 rcRect.bottom - rcRect.top,
399 FALSE);
401 // Set the pointer to the object
402 OPENFILENAMEW *ofn = (OPENFILENAMEW*)lParam;
403 SetWindowLongPtr(hdlg, GWLP_USERDATA, ofn->lCustData);
404 SetWindowLongPtr(hParentWnd, GWLP_USERDATA, ofn->lCustData);
405 pImpl = (FileOpenDialogImplWin32*)ofn->lCustData;
407 // Subclass the parent
408 pImpl->_base_window_proc = (WNDPROC)GetWindowLongPtr(hParentWnd, GWL_WNDPROC);
409 SetWindowLongPtr(hParentWnd, GWL_WNDPROC, (LONG_PTR)file_dialog_subclass_proc);
411 // Add a button to the toolbar
412 pImpl->_toolbar_wnd = FindWindowEx(hParentWnd, NULL, "ToolbarWindow32", NULL);
414 pImpl->_show_preview_button_bitmap = LoadBitmap(
415 hInstance, MAKEINTRESOURCE(IDC_SHOW_PREVIEW));
416 TBADDBITMAP tbAddBitmap = {NULL, (UINT)pImpl->_show_preview_button_bitmap};
417 const int iBitmapIndex = SendMessage(pImpl->_toolbar_wnd,
418 TB_ADDBITMAP, 1, (LPARAM)&tbAddBitmap);
420 TBBUTTON tbButton;
421 memset(&tbButton, 0, sizeof(TBBUTTON));
422 tbButton.iBitmap = iBitmapIndex;
423 tbButton.idCommand = IDC_SHOW_PREVIEW;
424 tbButton.fsState = (pImpl->_show_preview ? TBSTATE_CHECKED : 0)
425 | TBSTATE_ENABLED;
426 tbButton.fsStyle = TBSTYLE_CHECK;
427 tbButton.iString = (INT_PTR)_("Show Preview");
428 SendMessage(pImpl->_toolbar_wnd, TB_ADDBUTTONS, 1, (LPARAM)&tbButton);
430 // Create preview pane
431 register_preview_wnd_class();
433 pImpl->_mutex->lock();
435 pImpl->_file_dialog_wnd = hParentWnd;
437 pImpl->_preview_wnd =
438 CreateWindow(PreviewWindowClassName, "",
439 WS_CHILD | WS_VISIBLE,
440 0, 0, 100, 100, hParentWnd, NULL, hInstance, NULL);
441 SetWindowLongPtr(pImpl->_preview_wnd, GWLP_USERDATA, ofn->lCustData);
443 pImpl->_mutex->unlock();
445 pImpl->layout_dialog();
446 }
447 break;
449 case WM_NOTIFY:
450 {
452 OFNOTIFY *pOFNotify = reinterpret_cast<OFNOTIFY*>(lParam);
453 switch(pOFNotify->hdr.code)
454 {
455 case CDN_SELCHANGE:
456 {
457 if(pImpl != NULL)
458 {
459 // Get the file name
460 pImpl->_mutex->lock();
462 SendMessage(pOFNotify->hdr.hwndFrom, CDM_GETFILEPATH,
463 sizeof(pImpl->_path_string) / sizeof(wchar_t),
464 (LPARAM)pImpl->_path_string);
466 pImpl->_file_selected = true;
468 pImpl->_mutex->unlock();
470 //pImpl->file_selected();
471 }
472 }
473 break;
474 }
475 }
476 break;
478 case WM_CLOSE:
479 pImpl->_mutex->lock();
480 pImpl->_preview_file_size = 0;
482 pImpl->_file_dialog_wnd = NULL;
483 DestroyWindow(pImpl->_preview_wnd);
484 pImpl->_preview_wnd = NULL;
485 DeleteObject(pImpl->_show_preview_button_bitmap);
486 pImpl->_show_preview_button_bitmap = NULL;
487 pImpl->_mutex->unlock();
489 break;
490 }
492 // Use default dialog behaviour
493 return 0;
494 }
496 LRESULT CALLBACK FileOpenDialogImplWin32::file_dialog_subclass_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
497 {
498 FileOpenDialogImplWin32 *pImpl = (FileOpenDialogImplWin32*)
499 GetWindowLongPtr(hwnd, GWLP_USERDATA);
501 LRESULT lResult = CallWindowProc(pImpl->_base_window_proc, hwnd, uMsg, wParam, lParam);
503 switch(uMsg)
504 {
505 case WM_SHOWWINDOW:
506 if(wParam != 0)
507 pImpl->layout_dialog();
508 break;
510 case WM_SIZE:
511 pImpl->layout_dialog();
512 break;
514 case WM_COMMAND:
515 if(wParam == IDC_SHOW_PREVIEW)
516 {
517 const bool enable = SendMessage(pImpl->_toolbar_wnd,
518 TB_ISBUTTONCHECKED, IDC_SHOW_PREVIEW, 0) != 0;
519 pImpl->enable_preview(enable);
520 }
521 break;
522 }
524 return lResult;
525 }
527 LRESULT CALLBACK FileOpenDialogImplWin32::preview_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
528 {
529 const int CaptionPadding = 4;
530 const int IconSize = 32;
532 FileOpenDialogImplWin32 *pImpl = (FileOpenDialogImplWin32*)
533 GetWindowLongPtr(hwnd, GWLP_USERDATA);
535 LRESULT lResult = 0;
537 switch(uMsg)
538 {
539 case WM_ERASEBKGND:
540 // Do nothing to erase the background
541 // - otherwise there'll be flicker
542 lResult = 1;
543 break;
545 case WM_PAINT:
546 {
547 // Get the client rect
548 RECT rcClient;
549 GetClientRect(hwnd, &rcClient);
551 // Prepare to paint
552 PAINTSTRUCT paint_struct;
553 HDC dc = BeginPaint(hwnd, &paint_struct);
555 HFONT hCaptionFont = (HFONT)SendMessage(GetParent(hwnd),
556 WM_GETFONT, 0, 0);
557 HFONT hOldFont = (HFONT)SelectObject(dc, hCaptionFont);
558 SetBkMode(dc, TRANSPARENT);
560 pImpl->_mutex->lock();
562 //FillRect(dc, &client_rect, (HBRUSH)(COLOR_HOTLIGHT+1));
563 if(pImpl->_path_string[0] == 0)
564 {
565 FillRect(dc, &rcClient, (HBRUSH)(COLOR_3DFACE + 1));
566 DrawText(dc, _("No file selected"), -1, &rcClient,
567 DT_CENTER | DT_VCENTER | DT_NOPREFIX);
568 }
569 else if(pImpl->_preview_bitmap != NULL)
570 {
571 BITMAP bitmap;
572 GetObject(pImpl->_preview_bitmap, sizeof(bitmap), &bitmap);
573 const int destX = (rcClient.right - bitmap.bmWidth) / 2;
575 // Render the image
576 HDC hSrcDC = CreateCompatibleDC(dc);
577 HBITMAP hOldBitmap = (HBITMAP)SelectObject(hSrcDC, pImpl->_preview_bitmap);
579 BitBlt(dc, destX, 0, bitmap.bmWidth, bitmap.bmHeight,
580 hSrcDC, 0, 0, SRCCOPY);
582 SelectObject(hSrcDC, hOldBitmap);
583 DeleteDC(hSrcDC);
585 // Fill in the background area
586 HRGN hEraseRgn = CreateRectRgn(rcClient.left, rcClient.top,
587 rcClient.right, rcClient.bottom);
588 HRGN hImageRgn = CreateRectRgn(destX, 0,
589 destX + bitmap.bmWidth, bitmap.bmHeight);
590 CombineRgn(hEraseRgn, hEraseRgn, hImageRgn, RGN_DIFF);
592 FillRgn(dc, hEraseRgn, GetSysColorBrush(COLOR_3DFACE));
594 DeleteObject(hImageRgn);
595 DeleteObject(hEraseRgn);
597 // Draw the caption on
598 RECT rcCaptionRect = {rcClient.left,
599 rcClient.top + bitmap.bmHeight + CaptionPadding,
600 rcClient.right, rcClient.bottom};
602 WCHAR szCaption[_MAX_FNAME + 32];
603 const int iLength = pImpl->format_caption(
604 szCaption, sizeof(szCaption) / sizeof(WCHAR));
606 DrawTextW(dc, szCaption, iLength, &rcCaptionRect,
607 DT_CENTER | DT_TOP | DT_NOPREFIX | DT_PATH_ELLIPSIS);
608 }
609 else if(pImpl->_preview_file_icon != NULL)
610 {
611 FillRect(dc, &rcClient, (HBRUSH)(COLOR_3DFACE + 1));
613 // Draw the files icon
614 const int destX = (rcClient.right - IconSize) / 2;
615 DrawIconEx(dc, destX, 0, pImpl->_preview_file_icon,
616 IconSize, IconSize, 0, NULL,
617 DI_NORMAL | DI_COMPAT);
619 // Draw the caption on
620 RECT rcCaptionRect = {rcClient.left,
621 rcClient.top + IconSize + CaptionPadding,
622 rcClient.right, rcClient.bottom};
624 WCHAR szFileName[_MAX_FNAME], szCaption[_MAX_FNAME + 32];
625 _wsplitpath(pImpl->_path_string, NULL, NULL, szFileName, NULL);
627 const int iLength = snwprintf(szCaption,
628 sizeof(szCaption), L"%s\n%d kB",
629 szFileName, pImpl->_preview_file_size);
631 DrawTextW(dc, szCaption, iLength, &rcCaptionRect,
632 DT_CENTER | DT_TOP | DT_NOPREFIX | DT_PATH_ELLIPSIS);
633 }
634 else
635 {
636 // Can't show anything!
637 FillRect(dc, &rcClient, (HBRUSH)(COLOR_3DFACE + 1));
638 }
640 pImpl->_mutex->unlock();
642 // Finish painting
643 SelectObject(dc, hOldFont);
644 EndPaint(hwnd, &paint_struct);
645 }
647 break;
649 case WM_DESTROY:
650 pImpl->free_preview();
651 break;
653 default:
654 lResult = DefWindowProc(hwnd, uMsg, wParam, lParam);
655 break;
656 }
658 return lResult;
659 }
661 void FileOpenDialogImplWin32::enable_preview(bool enable)
662 {
663 _show_preview = enable;
665 // Relayout the dialog
666 ShowWindow(_preview_wnd, enable ? SW_SHOW : SW_HIDE);
667 layout_dialog();
669 // Load or unload the preview
670 if(enable)
671 {
672 _mutex->lock();
673 _file_selected = true;
674 _mutex->unlock();
675 }
676 else free_preview();
677 }
679 void FileOpenDialogImplWin32::layout_dialog()
680 {
681 union RECTPOINTS
682 {
683 RECT r;
684 POINT p[2];
685 };
687 const float MaxExtentScale = 2.0f / 3.0f;
689 RECT rcClient;
690 GetClientRect(_file_dialog_wnd, &rcClient);
692 // Re-layout the dialog
693 HWND hFileListWnd = GetDlgItem(_file_dialog_wnd, lst2);
694 HWND hFolderComboWnd = GetDlgItem(_file_dialog_wnd, cmb2);
697 RECT rcFolderComboRect;
698 RECTPOINTS rcFileList;
699 GetWindowRect(hFileListWnd, &rcFileList.r);
700 GetWindowRect(hFolderComboWnd, &rcFolderComboRect);
701 const int iPadding = rcFileList.r.top - rcFolderComboRect.bottom;
702 MapWindowPoints(NULL, _file_dialog_wnd, rcFileList.p, 2);
704 RECT rcPreview;
705 RECT rcBody = {rcFileList.r.left, rcFileList.r.top,
706 rcClient.right - iPadding, rcFileList.r.bottom};
707 rcFileList.r.right = rcBody.right;
709 if(_show_preview)
710 {
711 rcPreview.top = rcBody.top;
712 rcPreview.left = rcClient.right - (rcBody.bottom - rcBody.top);
713 const int iMaxExtent = (int)(MaxExtentScale * (float)(rcBody.left + rcBody.right)) + iPadding / 2;
714 if(rcPreview.left < iMaxExtent) rcPreview.left = iMaxExtent;
715 rcPreview.bottom = rcBody.bottom;
716 rcPreview.right = rcBody.right;
718 // Re-layout the preview box
719 _mutex->lock();
721 _preview_width = rcPreview.right - rcPreview.left;
722 _preview_height = rcPreview.bottom - rcPreview.top;
724 _mutex->unlock();
726 render_preview();
728 MoveWindow(_preview_wnd, rcPreview.left, rcPreview.top,
729 _preview_width, _preview_height, TRUE);
731 rcFileList.r.right = rcPreview.left - iPadding;
732 }
734 // Re-layout the file list box
735 MoveWindow(hFileListWnd, rcFileList.r.left, rcFileList.r.top,
736 rcFileList.r.right - rcFileList.r.left,
737 rcFileList.r.bottom - rcFileList.r.top, TRUE);
739 // Re-layout the toolbar
740 RECTPOINTS rcToolBar;
741 GetWindowRect(_toolbar_wnd, &rcToolBar.r);
742 MapWindowPoints(NULL, _file_dialog_wnd, rcToolBar.p, 2);
743 MoveWindow(_toolbar_wnd, rcToolBar.r.left, rcToolBar.r.top,
744 rcToolBar.r.right - rcToolBar.r.left, rcToolBar.r.bottom - rcToolBar.r.top, TRUE);
745 }
747 void FileOpenDialogImplWin32::file_selected()
748 {
749 // Destroy any previous previews
750 free_preview();
753 // Determine if the file exists
754 DWORD attributes = GetFileAttributesW(_path_string);
755 if(attributes == 0xFFFFFFFF ||
756 attributes == FILE_ATTRIBUTE_DIRECTORY)
757 {
758 InvalidateRect(_preview_wnd, NULL, FALSE);
759 return;
760 }
762 // Check the file exists and get the file size
763 HANDLE file_handle = CreateFileW(_path_string, GENERIC_READ,
764 FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
765 if(file_handle == INVALID_HANDLE_VALUE) return;
766 const DWORD file_size = GetFileSize(file_handle, NULL);
767 if (file_size == INVALID_FILE_SIZE) return;
768 _preview_file_size = file_size / 1024;
769 CloseHandle(file_handle);
771 if(_show_preview) load_preview();
772 }
774 void FileOpenDialogImplWin32::load_preview()
775 {
776 // Destroy any previous previews
777 free_preview();
779 // Try to get the file icon
780 SHFILEINFOW fileInfo;
781 if(SUCCEEDED(SHGetFileInfoW(_path_string, 0, &fileInfo,
782 sizeof(fileInfo), SHGFI_ICON | SHGFI_LARGEICON)))
783 _preview_file_icon = fileInfo.hIcon;
785 // Will this file be too big?
786 if(_preview_file_size > MaxPreviewFileSize)
787 {
788 InvalidateRect(_preview_wnd, NULL, FALSE);
789 return;
790 }
792 // Prepare to render a preview
793 const Glib::ustring svg = ".svg";
794 const Glib::ustring svgz = ".svgz";
795 const Glib::ustring path = utf16_to_ustring(_path_string);
797 bool success = false;
799 _preview_document_width = _preview_document_height = 0;
801 if ((dialogType == SVG_TYPES || dialogType == IMPORT_TYPES) &&
802 (hasSuffix(path, svg) || hasSuffix(path, svgz)))
803 success = set_svg_preview();
804 else if (isValidImageFile(path))
805 success = set_image_preview();
806 else {
807 // Show no preview
808 }
810 if(success) render_preview();
812 InvalidateRect(_preview_wnd, NULL, FALSE);
813 }
815 void FileOpenDialogImplWin32::free_preview()
816 {
817 _mutex->lock();
818 if(_preview_bitmap != NULL)
819 DeleteObject(_preview_bitmap);
820 _preview_bitmap = NULL;
822 if(_preview_file_icon != NULL)
823 DestroyIcon(_preview_file_icon);
824 _preview_file_icon = NULL;
826 _preview_bitmap_image.clear();
827 _mutex->unlock();
828 }
830 bool FileOpenDialogImplWin32::set_svg_preview()
831 {
832 const int PreviewSize = 512;
834 gchar *utf8string = g_utf16_to_utf8((const gunichar2*)_path_string,
835 _MAX_PATH, NULL, NULL, NULL);
836 SPDocument *svgDoc = sp_document_new (utf8string, true);
837 g_free(utf8string);
839 // Check the document loaded properly
840 if(svgDoc == NULL) return false;
841 if(svgDoc->root == NULL)
842 {
843 sp_document_unref(svgDoc);
844 return false;
845 }
847 // Get the size of the document
848 const double svgWidth = sp_document_width(svgDoc);
849 const double svgHeight = sp_document_height(svgDoc);
851 // Find the minimum scale to fit the image inside the preview area
852 const double scaleFactorX = PreviewSize / svgWidth;
853 const double scaleFactorY = PreviewSize / svgHeight;
854 const double scaleFactor = (scaleFactorX > scaleFactorY) ? scaleFactorY : scaleFactorX;
856 // Now get the resized values
857 const double scaledSvgWidth = scaleFactor * svgWidth;
858 const double scaledSvgHeight = scaleFactor * svgHeight;
860 NR::Rect area(NR::Point(0, 0), NR::Point(scaledSvgWidth, scaledSvgHeight));
861 NRRectL areaL = {0, 0, scaledSvgWidth, scaledSvgHeight};
862 NRRectL bbox = {0, 0, scaledSvgWidth, scaledSvgHeight};
864 // write object bbox to area
865 NR::Maybe<NR::Rect> maybeArea(area);
866 sp_document_ensure_up_to_date (svgDoc);
867 sp_item_invoke_bbox((SPItem *) svgDoc->root, &maybeArea,
868 sp_item_i2r_affine((SPItem *)(svgDoc->root)), TRUE);
870 NRArena *const arena = NRArena::create();
872 unsigned const key = sp_item_display_key_new(1);
874 NRArenaItem *root = sp_item_invoke_show((SPItem*)(svgDoc->root),
875 arena, key, SP_ITEM_SHOW_DISPLAY);
877 NRGC gc(NULL);
878 nr_matrix_set_scale(&gc.transform, scaleFactor, scaleFactor);
880 nr_arena_item_invoke_update (root, NULL, &gc,
881 NR_ARENA_ITEM_STATE_ALL, NR_ARENA_ITEM_STATE_NONE);
883 // Prepare a GDI compatible NRPixBlock
884 NRPixBlock pixBlock;
885 pixBlock.size = NR_PIXBLOCK_SIZE_BIG;
886 pixBlock.mode = NR_PIXBLOCK_MODE_R8G8B8;
887 pixBlock.empty = 1;
888 pixBlock.visible_area.x0 = pixBlock.area.x0 = 0;
889 pixBlock.visible_area.y0 = pixBlock.area.y0 = 0;
890 pixBlock.visible_area.x1 = pixBlock.area.x1 = scaledSvgWidth;
891 pixBlock.visible_area.y1 = pixBlock.area.y1 = scaledSvgHeight;
892 pixBlock.rs = 4 * ((3 * (int)scaledSvgWidth + 3) / 4);
893 pixBlock.data.px = g_try_new (unsigned char, pixBlock.rs * scaledSvgHeight);
895 // Fail if the pixblock failed to allocate
896 if(pixBlock.data.px == NULL)
897 {
898 sp_document_unref(svgDoc);
899 return false;
900 }
902 memset(pixBlock.data.px, 0xFF, pixBlock.rs * scaledSvgHeight);
904 memcpy(&root->bbox, &areaL, sizeof(areaL));
906 // Render the image
907 nr_arena_item_invoke_render(NULL, root, &bbox, &pixBlock, /*0*/NR_ARENA_ITEM_RENDER_NO_CACHE);
909 // Tidy up
910 sp_document_unref(svgDoc);
911 sp_item_invoke_hide((SPItem*)(svgDoc->root), key);
912 nr_arena_item_unref(root);
913 nr_object_unref((NRObject *) arena);
915 // Create the GDK pixbuf
916 _mutex->lock();
918 _preview_bitmap_image = Gdk::Pixbuf::create_from_data(
919 pixBlock.data.px, Gdk::COLORSPACE_RGB, false, 8,
920 (int)scaledSvgWidth, (int)scaledSvgHeight, pixBlock.rs,
921 sigc::ptr_fun(destroy_svg_rendering));
923 _preview_document_width = scaledSvgWidth;
924 _preview_document_height = scaledSvgHeight;
925 _preview_image_width = svgWidth;
926 _preview_image_height = svgHeight;
928 _mutex->unlock();
930 return true;
931 }
933 void FileOpenDialogImplWin32::destroy_svg_rendering(const guint8 *buffer)
934 {
935 g_assert(buffer != NULL);
936 g_free((void*)buffer);
937 }
939 bool FileOpenDialogImplWin32::set_image_preview()
940 {
941 const Glib::ustring path = utf16_to_ustring(_path_string, _MAX_PATH);
943 _mutex->lock();
944 _preview_bitmap_image = Gdk::Pixbuf::create_from_file(path);
945 if(!_preview_bitmap_image) return false;
947 _preview_image_width = _preview_bitmap_image->get_width();
948 _preview_document_width = _preview_image_width;
949 _preview_image_height = _preview_bitmap_image->get_height();
950 _preview_document_height = _preview_image_height;
952 _mutex->unlock();
954 return true;
955 }
957 void FileOpenDialogImplWin32::render_preview()
958 {
959 double x, y;
960 const double blurRadius = 8;
961 const double halfBlurRadius = blurRadius / 2;
962 const int shaddowOffsetX = 0;
963 const int shaddowOffsetY = 2;
964 const int pagePadding = 5;
965 const double shaddowAlpha = 0.75;
967 // Is the preview showing?
968 if(!_show_preview)
969 return;
971 // Do we have anything to render?
972 _mutex->lock();
974 if(!_preview_bitmap_image)
975 {
976 _mutex->unlock();
977 return;
978 }
980 // Tidy up any previous bitmap renderings
981 if(_preview_bitmap != NULL)
982 DeleteObject(_preview_bitmap);
983 _preview_bitmap = NULL;
985 // Calculate the size of the caption
986 int captionHeight = 0;
988 if(_preview_wnd != NULL)
989 {
990 RECT rcCaptionRect;
991 WCHAR szCaption[_MAX_FNAME + 32];
992 const int iLength = format_caption(szCaption,
993 sizeof(szCaption) / sizeof(WCHAR));
995 HDC dc = GetDC(_preview_wnd);
996 DrawTextW(dc, szCaption, iLength, &rcCaptionRect,
997 DT_CENTER | DT_TOP | DT_NOPREFIX | DT_PATH_ELLIPSIS | DT_CALCRECT);
998 ReleaseDC(_preview_wnd, dc);
1000 captionHeight = rcCaptionRect.bottom - rcCaptionRect.top;
1001 }
1003 // Find the minimum scale to fit the image inside the preview area
1004 const double scaleFactorX =
1005 ((double)_preview_width - pagePadding * 2 - blurRadius) / _preview_document_width;
1006 const double scaleFactorY =
1007 ((double)_preview_height - pagePadding * 2
1008 - shaddowOffsetY - halfBlurRadius - captionHeight) / _preview_document_height;
1009 double scaleFactor = (scaleFactorX > scaleFactorY) ? scaleFactorY : scaleFactorX;
1010 scaleFactor = (scaleFactor > 1.0) ? 1.0 : scaleFactor;
1012 // Now get the resized values
1013 const double scaledSvgWidth = scaleFactor * _preview_document_width;
1014 const double scaledSvgHeight = scaleFactor * _preview_document_height;
1016 const int svgX = pagePadding + halfBlurRadius;
1017 const int svgY = pagePadding;
1019 const int frameX = svgX - pagePadding;
1020 const int frameY = svgY - pagePadding;
1021 const int frameWidth = scaledSvgWidth + pagePadding * 2;
1022 const int frameHeight = scaledSvgHeight + pagePadding * 2;
1024 const int totalWidth = (int)ceil(frameWidth + blurRadius);
1025 const int totalHeight = (int)ceil(frameHeight + blurRadius);
1027 // Prepare the drawing surface
1028 HDC hDC = GetDC(_preview_wnd);
1029 HDC hMemDC = CreateCompatibleDC(hDC);
1030 _preview_bitmap = CreateCompatibleBitmap(hDC, totalWidth, totalHeight);
1031 HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemDC, _preview_bitmap);
1032 Cairo::RefPtr<Win32Surface> surface = Win32Surface::create(hMemDC);
1033 Cairo::RefPtr<Context> context = Context::create(surface);
1035 // Paint the background to match the dialog colour
1036 const COLORREF background = GetSysColor(COLOR_3DFACE);
1037 context->set_source_rgb(
1038 GetRValue(background) / 255.0,
1039 GetGValue(background) / 255.0,
1040 GetBValue(background) / 255.0);
1041 context->paint();
1043 //----- Draw the drop shaddow -----//
1045 // Left Edge
1046 x = frameX + shaddowOffsetX - halfBlurRadius;
1047 Cairo::RefPtr<LinearGradient> leftEdgeFade = LinearGradient::create(
1048 x, 0.0, x + blurRadius, 0.0);
1049 leftEdgeFade->add_color_stop_rgba (0, 0, 0, 0, 0);
1050 leftEdgeFade->add_color_stop_rgba (1, 0, 0, 0, shaddowAlpha);
1051 context->set_source(leftEdgeFade);
1052 context->rectangle (x, frameY + shaddowOffsetY + halfBlurRadius,
1053 blurRadius, frameHeight - blurRadius);
1054 context->fill();
1056 // Right Edge
1057 x = frameX + frameWidth + shaddowOffsetX - halfBlurRadius;
1058 Cairo::RefPtr<LinearGradient> rightEdgeFade = LinearGradient::create(
1059 x, 0.0, x + blurRadius, 0.0);
1060 rightEdgeFade->add_color_stop_rgba (0, 0, 0, 0, shaddowAlpha);
1061 rightEdgeFade->add_color_stop_rgba (1, 0, 0, 0, 0);
1062 context->set_source(rightEdgeFade);
1063 context->rectangle (frameX + frameWidth + shaddowOffsetX - halfBlurRadius,
1064 frameY + shaddowOffsetY + halfBlurRadius,
1065 blurRadius, frameHeight - blurRadius);
1066 context->fill();
1068 // Top Edge
1069 y = frameY + shaddowOffsetY - halfBlurRadius;
1070 Cairo::RefPtr<LinearGradient> topEdgeFade = LinearGradient::create(
1071 0.0, y, 0.0, y + blurRadius);
1072 topEdgeFade->add_color_stop_rgba (0, 0, 0, 0, 0);
1073 topEdgeFade->add_color_stop_rgba (1, 0, 0, 0, shaddowAlpha);
1074 context->set_source(topEdgeFade);
1075 context->rectangle (frameX + shaddowOffsetX + halfBlurRadius, y,
1076 frameWidth - blurRadius, blurRadius);
1077 context->fill();
1079 // Bottom Edge
1080 y = frameY + frameHeight + shaddowOffsetY - halfBlurRadius;
1081 Cairo::RefPtr<LinearGradient> bottomEdgeFade = LinearGradient::create(
1082 0.0, y, 0.0, y + blurRadius);
1083 bottomEdgeFade->add_color_stop_rgba (0, 0, 0, 0, shaddowAlpha);
1084 bottomEdgeFade->add_color_stop_rgba (1, 0, 0, 0, 0);
1085 context->set_source(bottomEdgeFade);
1086 context->rectangle (frameX + shaddowOffsetX + halfBlurRadius, y,
1087 frameWidth - blurRadius, blurRadius);
1088 context->fill();
1090 // Top Left Corner
1091 x = frameX + shaddowOffsetX - halfBlurRadius;
1092 y = frameY + shaddowOffsetY - halfBlurRadius;
1093 Cairo::RefPtr<RadialGradient> topLeftCornerFade = RadialGradient::create(
1094 x + blurRadius, y + blurRadius, 0, x + blurRadius, y + blurRadius, blurRadius);
1095 topLeftCornerFade->add_color_stop_rgba (0, 0, 0, 0, shaddowAlpha);
1096 topLeftCornerFade->add_color_stop_rgba (1, 0, 0, 0, 0);
1097 context->set_source(topLeftCornerFade);
1098 context->rectangle (x, y, blurRadius, blurRadius);
1099 context->fill();
1101 // Top Right Corner
1102 x = frameX + frameWidth + shaddowOffsetX - halfBlurRadius;
1103 y = frameY + shaddowOffsetY - halfBlurRadius;
1104 Cairo::RefPtr<RadialGradient> topRightCornerFade = RadialGradient::create(
1105 x, y + blurRadius, 0, x, y + blurRadius, blurRadius);
1106 topRightCornerFade->add_color_stop_rgba (0, 0, 0, 0, shaddowAlpha);
1107 topRightCornerFade->add_color_stop_rgba (1, 0, 0, 0, 0);
1108 context->set_source(topRightCornerFade);
1109 context->rectangle (x, y, blurRadius, blurRadius);
1110 context->fill();
1112 // Bottom Left Corner
1113 x = frameX + shaddowOffsetX - halfBlurRadius;
1114 y = frameY + frameHeight + shaddowOffsetY - halfBlurRadius;
1115 Cairo::RefPtr<RadialGradient> bottomLeftCornerFade = RadialGradient::create(
1116 x + blurRadius, y, 0, x + blurRadius, y, blurRadius);
1117 bottomLeftCornerFade->add_color_stop_rgba (0, 0, 0, 0, shaddowAlpha);
1118 bottomLeftCornerFade->add_color_stop_rgba (1, 0, 0, 0, 0);
1119 context->set_source(bottomLeftCornerFade);
1120 context->rectangle (x, y, blurRadius, blurRadius);
1121 context->fill();
1123 // Bottom Right Corner
1124 x = frameX + frameWidth + shaddowOffsetX - halfBlurRadius;
1125 y = frameY + frameHeight + shaddowOffsetY - halfBlurRadius;
1126 Cairo::RefPtr<RadialGradient> bottomRightCornerFade = RadialGradient::create(
1127 x, y, 0, x, y, blurRadius);
1128 bottomRightCornerFade->add_color_stop_rgba (0, 0, 0, 0, shaddowAlpha);
1129 bottomRightCornerFade->add_color_stop_rgba (1, 0, 0, 0, 0);
1130 context->set_source(bottomRightCornerFade);
1131 context->rectangle (frameX + frameWidth + shaddowOffsetX - halfBlurRadius,
1132 frameY + frameHeight + shaddowOffsetY - halfBlurRadius,
1133 blurRadius, blurRadius);
1134 context->fill();
1136 // Draw the frame
1137 context->set_line_width(1);
1138 context->rectangle (frameX, frameY, frameWidth, frameHeight);
1140 context->set_source_rgb(1.0, 1.0, 1.0);
1141 context->fill_preserve();
1142 context->set_source_rgb(0.25, 0.25, 0.25);
1143 context->stroke_preserve();
1145 // Draw the image
1147 if(_preview_bitmap_image) // Is the image a pixbuf?
1148 {
1149 // Set the transformation
1150 const Matrix matrix = {
1151 scaleFactor, 0,
1152 0, scaleFactor,
1153 svgX, svgY };
1154 context->set_matrix (matrix);
1156 // Render the image
1157 set_source_pixbuf (context, _preview_bitmap_image, 0, 0);
1158 context->paint();
1160 // Reset the transformation
1161 context->set_identity_matrix();
1162 }
1164 // Draw the inner frame
1165 context->set_source_rgb(0.75, 0.75, 0.75);
1166 context->rectangle (svgX, svgY, scaledSvgWidth, scaledSvgHeight);
1167 context->stroke();
1169 _mutex->unlock();
1171 // Finish drawing
1172 surface->finish();
1173 SelectObject(hMemDC, hOldBitmap) ;
1174 DeleteDC(hMemDC);
1176 // Refresh the preview pane
1177 InvalidateRect(_preview_wnd, NULL, FALSE);
1178 }
1180 int FileOpenDialogImplWin32::format_caption(wchar_t *caption, int caption_size)
1181 {
1182 wchar_t szFileName[_MAX_FNAME];
1183 _wsplitpath(_path_string, NULL, NULL, szFileName, NULL);
1185 return snwprintf(caption, caption_size,
1186 L"%s\n%d kB\n%d \xD7 %d", szFileName, _preview_file_size,
1187 (int)_preview_document_width, (int)_preview_document_height);
1188 }
1190 /**
1191 * Show this dialog modally. Return true if user hits [OK]
1192 */
1193 bool
1194 FileOpenDialogImplWin32::show()
1195 {
1196 // We can only run one worker thread at a time
1197 //if(_mutex != NULL) return false;
1199 if(!Glib::thread_supported())
1200 Glib::thread_init();
1202 _result = false;
1203 _finished = false;
1204 _file_selected = false;
1205 _mutex = new Glib::Mutex();
1206 _main_loop = g_main_loop_new(g_main_context_default(), FALSE);
1208 if(Glib::Thread::create(sigc::mem_fun(*this, &FileOpenDialogImplWin32::GetOpenFileName_thread), true))
1209 {
1210 while(1)
1211 {
1212 g_main_context_iteration(g_main_context_default(), FALSE);
1214 if(_mutex->trylock())
1215 {
1216 // Read mutexed data
1217 const bool finished = _finished;
1218 const bool is_file_selected = _file_selected;
1219 _file_selected = false;
1220 _mutex->unlock();
1222 if(finished) break;
1223 if(is_file_selected) file_selected();
1224 }
1226 Sleep(10);
1227 }
1228 //g_main_loop_run(_main_loop);
1229 }
1231 // Tidy up
1232 delete _mutex;
1233 _mutex = NULL;
1235 return _result;
1236 }
1238 /**
1239 * To Get Multiple filenames selected at-once.
1240 */
1241 std::vector<Glib::ustring>FileOpenDialogImplWin32::getFilenames()
1242 {
1243 std::vector<Glib::ustring> result;
1244 result.push_back(getFilename());
1245 return result;
1246 }
1249 /*#########################################################################
1250 ### F I L E S A V E
1251 #########################################################################*/
1253 /**
1254 * Constructor
1255 */
1256 FileSaveDialogImplWin32::FileSaveDialogImplWin32(Gtk::Window &parent,
1257 const Glib::ustring &dir,
1258 FileDialogType fileTypes,
1259 const char *title,
1260 const Glib::ustring &/*default_key*/) :
1261 FileDialogBaseWin32(parent, dir, title, fileTypes, "dialogs.save_as")
1262 {
1263 _main_loop = NULL;
1265 createFilterMenu();
1266 }
1268 FileSaveDialogImplWin32::~FileSaveDialogImplWin32()
1269 {
1270 }
1272 void FileSaveDialogImplWin32::createFilterMenu()
1273 {
1274 list<Filter> filter_list;
1276 knownExtensions.clear();
1278 // Compose the filter string
1279 Glib::ustring all_inkscape_files_filter, all_image_files_filter;
1280 Inkscape::Extension::DB::OutputList extension_list;
1281 Inkscape::Extension::db.get_output_list(extension_list);
1283 int filter_count = 0;
1284 int filter_length = 0;
1286 for (Inkscape::Extension::DB::OutputList::iterator current_item = extension_list.begin();
1287 current_item != extension_list.end(); current_item++)
1288 {
1289 Inkscape::Extension::Output *omod = *current_item;
1290 if (omod->deactivated()) continue;
1292 filter_count++;
1294 Filter filter;
1296 // Extension
1297 const gchar *filter_extension = omod->get_extension();
1298 filter.filter = g_utf8_to_utf16(
1299 filter_extension, -1, NULL, &filter.filter_length, NULL);
1300 knownExtensions.insert( Glib::ustring(filter_extension).casefold() );
1302 // Type
1303 filter.name = g_utf8_to_utf16(
1304 omod->get_filetypename(), -1, NULL, &filter.name_length, NULL);
1306 filter.mod = omod;
1308 filter_length += filter.name_length +
1309 filter.filter_length + 3; // Add 3 for two \0s and a *
1311 filter_list.push_back(filter);
1312 }
1314 int extension_index = 0;
1315 _extension_map = new Inkscape::Extension::Extension*[filter_count];
1317 _filter = new wchar_t[filter_length];
1318 wchar_t *filterptr = _filter;
1320 for(list<Filter>::iterator filter_iterator = filter_list.begin();
1321 filter_iterator != filter_list.end(); filter_iterator++)
1322 {
1323 const Filter &filter = *filter_iterator;
1325 memcpy(filterptr, filter.name, filter.name_length * 2);
1326 filterptr += filter.name_length;
1327 g_free(filter.name);
1329 *(filterptr++) = L'\0';
1330 *(filterptr++) = L'*';
1332 memcpy(filterptr, filter.filter, filter.filter_length * 2);
1333 filterptr += filter.filter_length;
1334 g_free(filter.filter);
1336 *(filterptr++) = L'\0';
1338 // Associate this input extension with the file type name
1339 _extension_map[extension_index++] = filter.mod;
1340 }
1341 *(filterptr++) = 0;
1343 _filterIndex = 0;
1344 }
1346 void FileSaveDialogImplWin32::GetSaveFileName_thread()
1347 {
1348 OPENFILENAMEEXW ofn;
1350 g_assert(this != NULL);
1351 //g_assert(_mutex != NULL);
1352 g_assert(_main_loop != NULL);
1354 gunichar2* current_directory_string = g_utf8_to_utf16(
1355 _current_directory.data(), -1, NULL, NULL, NULL);
1357 // Copy the selected file name, converting from UTF-8 to UTF-16
1358 memset(_path_string, 0, sizeof(_path_string));
1359 gunichar2* utf16_path_string = g_utf8_to_utf16(
1360 myFilename.data(), -1, NULL, NULL, NULL);
1361 wcsncpy(_path_string, (wchar_t*)utf16_path_string, _MAX_PATH);
1362 g_free(utf16_path_string);
1364 ZeroMemory(&ofn, sizeof(ofn));
1365 ofn.lStructSize = sizeof(ofn);
1366 ofn.hwndOwner = _ownerHwnd;
1367 ofn.lpstrFile = _path_string;
1368 ofn.nMaxFile = _MAX_PATH;
1369 ofn.nFilterIndex = _filterIndex;
1370 ofn.lpstrFileTitle = NULL;
1371 ofn.nMaxFileTitle = 0;
1372 ofn.lpstrInitialDir = (wchar_t*)current_directory_string;
1373 ofn.lpstrTitle = _title;
1374 ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
1375 ofn.lpstrFilter = _filter;
1376 ofn.nFilterIndex = _filterIndex;
1378 _result = GetSaveFileNameW(&ofn) != 0;
1380 _filterIndex = ofn.nFilterIndex;
1381 _extension = _extension_map[ofn.nFilterIndex];
1383 // Copy the selected file name, converting from UTF-16 to UTF-8
1384 myFilename = utf16_to_ustring(_path_string, _MAX_PATH);
1386 //_mutex->lock();
1387 //_finished = true;
1388 //_mutex->unlock();
1391 // Tidy up
1392 g_free(current_directory_string);
1394 g_main_loop_quit(_main_loop);
1395 }
1397 /**
1398 * Show this dialog modally. Return true if user hits [OK]
1399 */
1400 bool
1401 FileSaveDialogImplWin32::show()
1402 {
1403 // We can only run one worker thread at a time
1404 //if(_mutex != NULL) return false;
1406 if(!Glib::thread_supported())
1407 Glib::thread_init();
1409 _result = false;
1410 //_finished = false;
1411 //_mutex = new Glib::Mutex();
1412 _main_loop = g_main_loop_new(g_main_context_default(), FALSE);
1414 if(Glib::Thread::create(sigc::mem_fun(*this, &FileSaveDialogImplWin32::GetSaveFileName_thread), true))
1415 {
1416 /*while(1)
1417 {
1418 // While the dialog runs - keep the main UI alive
1419 g_main_context_iteration(g_main_context_default(), FALSE);
1421 if(_mutex->trylock())
1422 {
1423 if(_finished) break;
1424 _mutex->unlock();
1425 }
1427 Sleep(10);
1428 }*/
1429 g_main_loop_run(_main_loop);
1430 }
1431 //delete _mutex;
1432 //_mutex = NULL;
1434 if(_result)
1435 appendExtension(myFilename, (Inkscape::Extension::Output*)_extension);
1437 return _result;
1438 }
1440 void FileSaveDialogImplWin32::setSelectionType( Inkscape::Extension::Extension * /*key*/ )
1441 {
1442 // If no pointer to extension is passed in, look up based on filename extension.
1444 }
1446 }
1447 }
1448 }
1450 #endif
1452 /*
1453 Local Variables:
1454 mode:c++
1455 c-file-style:"stroustrup"
1456 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1457 indent-tabs-mode:nil
1458 fill-column:99
1459 End:
1460 */
1461 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :