Code

Line-end fix
[inkscape.git] / src / ui / dialog / filedialogimpl-win32.cpp
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)
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());
117 FileDialogBaseWin32::~FileDialogBaseWin32()
119     g_free(_title);
122 Inkscape::Extension::Extension *FileDialogBaseWin32::getSelectionType()
124     return _extension;
127 Glib::ustring FileDialogBaseWin32::getCurrentDirectory()
129     return _current_directory;
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")
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();
170 /**
171  * Destructor
172  */
173 FileOpenDialogImplWin32::~FileOpenDialogImplWin32()
175     if(_filter != NULL)
176         delete[] _filter;
177     if(_extension_map != NULL)
178         delete[] _extension_map;
181 void FileOpenDialogImplWin32::createFilterMenu()
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;
305 void FileOpenDialogImplWin32::GetOpenFileName_thread()
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);
360 void FileOpenDialogImplWin32::register_preview_wnd_class()
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);
380 UINT_PTR CALLBACK FileOpenDialogImplWin32::GetOpenFileName_hookproc(
381     HWND hdlg, UINT uiMsg, WPARAM, LPARAM lParam)
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;
496 LRESULT CALLBACK FileOpenDialogImplWin32::file_dialog_subclass_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
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;
527 LRESULT CALLBACK FileOpenDialogImplWin32::preview_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
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;
661 void FileOpenDialogImplWin32::enable_preview(bool enable)
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();
679 void FileOpenDialogImplWin32::layout_dialog()
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);
747 void FileOpenDialogImplWin32::file_selected()
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();
774 void FileOpenDialogImplWin32::load_preview()
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);
815 void FileOpenDialogImplWin32::free_preview()
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();
830 bool FileOpenDialogImplWin32::set_svg_preview()
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;
933 void FileOpenDialogImplWin32::destroy_svg_rendering(const guint8 *buffer)
935     g_assert(buffer != NULL);
936     g_free((void*)buffer);
939 bool FileOpenDialogImplWin32::set_image_preview()
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;
957 void FileOpenDialogImplWin32::render_preview()
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);
1180 int FileOpenDialogImplWin32::format_caption(wchar_t *caption, int caption_size)
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);
1190 /**
1191  * Show this dialog modally.  Return true if user hits [OK]
1192  */
1193 bool
1194 FileOpenDialogImplWin32::show()
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;
1238 /**
1239  * To Get Multiple filenames selected at-once.
1240  */
1241 std::vector<Glib::ustring>FileOpenDialogImplWin32::getFilenames()
1243     std::vector<Glib::ustring> result;
1244     result.push_back(getFilename());
1245     return result;
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")
1263     _main_loop = NULL;
1265     createFilterMenu();
1268 FileSaveDialogImplWin32::~FileSaveDialogImplWin32()
1272 void FileSaveDialogImplWin32::createFilterMenu()
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;
1346 void FileSaveDialogImplWin32::GetSaveFileName_thread()
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);
1397 /**
1398  * Show this dialog modally.  Return true if user hits [OK]
1399  */
1400 bool
1401 FileSaveDialogImplWin32::show()
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;
1440 void FileSaveDialogImplWin32::setSelectionType( Inkscape::Extension::Extension * /*key*/ )
1442     // If no pointer to extension is passed in, look up based on filename extension.
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 :