1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 #include "filedialog.h"
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <ctype.h>
29 #include <sys/stat.h>
30 #include <time.h>
31 #include <dirent.h>
32 #include <fnmatch.h>
33 #include <errno.h>
34 #include <inttypes.h>
35 #include <unistd.h>
36 #include <fcntl.h>
37
38 #include <Xm/PrimitiveP.h>
39 #include <X11/CoreP.h>
40
41 "../Microline/XmL/Grid.h"#include
42
43 #include <X11/Xresource.h>
44
45
46
47 #include "nedit_malloc.h"
48 #include "utils.h"
49 #include "fileUtils.h"
50 #include "getfiles.h"
51 #include "misc.h"
52 #include "textfield.h"
53 #include "ec_glob.h"
54 #include "pathutils.h"
55
56 #include "../source/preferences.h"
57 #include "../source/filter.h"
58
59 #include "DialogF.h"
60
61 #define WIDGET_SPACING 5
62 #define WINDOW_SPACING 8
63
64 #define BUTTON_EXTRA_SPACE 4
65
66 #define DATE_FORMAT_SAME_YEAR "%b %d %H:%M"
67 #define DATE_FORMAT_OTHER_YEAR "%b %d %Y"
68
69 #define KB_SUFFIX "KiB"
70 #define MB_SUFFIX "MiB"
71 #define GB_SUFFIX "GiB"
72 #define TB_SUFFIX "TiB"
73
74 static int pixmaps_initialized =
0;
75 static int pixmaps_error =
0;
76
77 static Pixmap newFolderIcon16;
78 static Pixmap newFolderIcon24;
79 static Pixmap newFolderIcon32;
80
81 static XColor bgColor;
82
83 static int LastView = -
1;
84 static char *LastFilter;
85
86 #define FSB_ENABLE_DETAIL
87
88 const char *newFolder16Data =
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
89 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
90 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
91 "\377\377\377\377\377\377\377\377\377\377>>>\377\064\064\064\377\064\064\064\377"
92 "\064\064\064\377\064\064\064\377ZZZ\377\377\377\377\377\377\377\377\377\377\377"
93 "\377\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\377\377\377\377\377\377"
94 "\377\377\377\377\377\377\064\064\064\377\177\177\177\377\177\177\177\377\177"
95 "\177\177\377www\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377\000"
96 "\000\000\377\363\267/\377\363\267/\377\000\000\000\377\064\064\064\377\064\064\064\377\343"
97 "\343\343\377\064\064\064\377ooo\377ooo\377ooo\377ooo\377ooo\377ooo\377ooo\377"
98 "ooo\377\000\000\000\377\363\267/\377\363\267/\377\000\000\000\377ooo\377^^^\377;;;\377"
99 "\064\064\064\377ooo\377ooo\377ooo\377ooo\377ooo\377\000\000\000\377\000\000\000\377\000\000"
100 "\000\377\000\000\000\377\363\267/\377\363\267/\377\000\000\000\377\000\000\000\377\000\000\000\377"
101 "\000\000\000\377\061\061\061\377///\377---\377---\377---\377---\377\000\000\000\377\363"
102 "\267/\377\363\267/\377\363\267/\377\363\267/\377\363\267/\377\363\267/\377"
103 "\363\267/\377\363\267/\377\000\000\000\377\061\061\061\377MMM\377MMM\377MMM\377MM"
104 "M\377MMM\377\000\000\000\377\363\267/\377\363\267/\377\363\267/\377\363\267/\377"
105 "\363\267/\377\363\267/\377\363\267/\377\363\267/\377\000\000\000\377\064\064\064\377"
106 "MMM\377MMM\377MMM\377MMM\377MMM\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377"
107 "\363\267/\377\363\267/\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\064\064"
108 "\064\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377\000\000\000\377"
109 "\363\267/\377\363\267/\377\000\000\000\377MMM\377MMM\377\064\064\064\377\064\064\064"
110 "\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377\000\000\000\377\363"
111 "\267/\377\363\267/\377\000\000\000\377MMM\377MMM\377\064\064\064\377\064\064\064\377"
112 "MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377\000\000\000\377\000\000\000"
113 "\377\000\000\000\377\000\000\000\377MMM\377MMM\377\064\064\064\377\064\064\064\377MMM\377M"
114 "MM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM"
115 "\377MMM\377MMM\377\064\064\064\377\064\064\064\377MMM\377MMM\377MMM\377MMM\377"
116 "MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377\064"
117 "\064\064\377\064\064\064\377MMM\377MMM\377MMM\377MMM\377KKK\377KKK\377KKK\377"
118 "KKK\377KKK\377JJJ\377JJJ\377GGG\377GGG\377GGG\377\064\064\064\377ZZZ\377\064"
119 "\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377"
120 "\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064"
121 "\377\064\064\064\377\064\064\064\377ZZZ\377\377\377\377\377\377\377\377\377\377"
122 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
123 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
124 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
125 "\377";
126
127 const char *newFolder24Data =
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
128 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
129 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
130 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
131 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
132 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
133 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
134 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
135 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
136 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
137 "\377\377\377\377\377\377\377\377\377\377\377\377EEE\377\064\064\064\377\064\064"
138 "\064\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377\065\065\065\377"
139 "uuu\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
140 "\377\377\377\377\377\377\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000"
141 "\000\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\064"
142 "\064\064\377eee\377\202\202\202\377\202\202\202\377\202\202\202\377\202\202"
143 "\202\377xxx\377fff\377AAA\377uuu\377\354\354\354\377\377\377\377\377\377"
144 "\377\377\377\377\377\377\377\377\377\377\377\000\000\000\377\363\267/\377\363\267"
145 "/\377\363\267/\377\000\000\000\377\377\377\377\377\377\377\377\377\377\377\377"
146 "\377\374\374\374\377\064\064\064\377[[[\377ttt\377ttt\377ttt\377ttt\377ttt\377"
147 "rrr\377eee\377EEE\377\071\071\071\377\071\071\071\377\071\071\071\377\071\071\071\377"
148 "\070\070\070\377\000\000\000\377\363\267/\377\363\267/\377\363\267/\377\000\000\000\377"
149 "\070\070\070\377\064\064\064\377;;;\377\264\264\264\377\064\064\064\377XXX\377ooo"
150 "\377ooo\377ooo\377ooo\377ooo\377ooo\377ooo\377kkk\377hhh\377hhh\377hhh\377"
151 "hhh\377hhh\377\000\000\000\377\363\267/\377\363\267/\377\363\267/\377\000\000\000\377"
152 "hhh\377hhh\377SSS\377\070\070\070\377\064\064\064\377XXX\377ooo\377ooo\377ooo\377"
153 "ooo\377ooo\377ooo\377ooo\377ooo\377ooo\377\000\000\000\377\000\000\000\377\000\000\000\377"
154 "\000\000\000\377\000\000\000\377\363\267/\377\363\267/\377\363\267/\377\000\000\000\377\000\000"
155 "\000\377\000\000\000\377\000\000\000\377\000\000\000\377\064\064\064\377HHH\377VVV\377UUU\377UU"
156 "U\377UUU\377UUU\377UUU\377UUU\377UUU\377UUU\377\000\000\000\377\363\267/\377\363"
157 "\267/\377\363\267/\377\363\267/\377\363\267/\377\363\267/\377\363\267/\377"
158 "\363\267/\377\363\267/\377\363\267/\377\363\267/\377\000\000\000\377///\377///"
159 "\377...\377...\377...\377...\377...\377...\377...\377...\377...\377\000\000\000"
160 "\377\363\267/\377\363\267/\377\363\267/\377\363\267/\377\363\267/\377\363"
161 "\267/\377\363\267/\377\363\267/\377\363\267/\377\363\267/\377\363\267/\377"
162 "\000\000\000\377///\377@@@\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377"
163 "MMM\377MMM\377\000\000\000\377\363\267/\377\363\267/\377\363\267/\377\363\267/"
164 "\377\363\267/\377\363\267/\377\363\267/\377\363\267/\377\363\267/\377\363"
165 "\267/\377\363\267/\377\000\000\000\377\064\064\064\377BBB\377MMM\377MMM\377MMM\377"
166 "MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377\000\000\000\377\000\000\000\377\000\000\000\377"
167 "\000\000\000\377\000\000\000\377\363\267/\377\363\267/\377\363\267/\377\000\000\000\377\000\000"
168 "\000\377\000\000\000\377\000\000\000\377\000\000\000\377\064\064\064\377BBB\377MMM\377MMM\377MM"
169 "M\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377"
170 "\000\000\000\377\363\267/\377\363\267/\377\363\267/\377\000\000\000\377MMM\377MMM\377"
171 "BBB\377\064\064\064\377\064\064\064\377BBB\377MMM\377MMM\377MMM\377MMM\377MMM\377"
172 "MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377\000\000\000\377\363\267"
173 "/\377\363\267/\377\363\267/\377\000\000\000\377MMM\377MMM\377BBB\377\064\064\064\377"
174 "\064\064\064\377BBB\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM"
175 "\377MMM\377MMM\377MMM\377MMM\377MMM\377\000\000\000\377\363\267/\377\363\267/\377"
176 "\363\267/\377\000\000\000\377MMM\377MMM\377BBB\377\064\064\064\377\064\064\064\377BB"
177 "B\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377"
178 "MMM\377MMM\377MMM\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377M"
179 "MM\377MMM\377BBB\377\064\064\064\377\064\064\064\377BBB\377MMM\377MMM\377MMM\377"
180 "MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MM"
181 "M\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377BBB\377\064\064\064\377\064\064"
182 "\064\377BBB\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MM"
183 "M\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377"
184 "MMM\377BBB\377\064\064\064\377\064\064\064\377BBB\377MMM\377MMM\377MMM\377MMM\377"
185 "MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MM"
186 "M\377MMM\377MMM\377MMM\377MMM\377MMM\377BBB\377\064\064\064\377\064\064\064\377"
187 "BBB\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MM"
188 "M\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377"
189 "BBB\377\064\064\064\377\064\064\064\377BBB\377MMM\377MMM\377MMM\377MMM\377MMM\377"
190 "MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MM"
191 "M\377MMM\377MMM\377MMM\377MMM\377BBB\377\064\064\064\377\064\064\064\377BBB\377"
192 "MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MM"
193 "M\377MMM\377MMM\377MMM\377MMM\377MMM\377KKK\377KKK\377KKK\377KKK\377@@@\377"
194 "\064\064\064\377\064\064\064\377BBB\377MMM\377MMM\377MMM\377MMM\377MMM\377KKK\377"
195 "III\377III\377III\377III\377III\377III\377III\377GGG\377GGG\377GGG\377FF"
196 "F\377FFF\377FFF\377FFF\377>>>\377\064\064\064\377EEE\377\064\064\064\377\064\064"
197 "\064\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377"
198 "\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064"
199 "\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377\064"
200 "\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377EEE\377\377\377\377\377"
201 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
202 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
203 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
204 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
205 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
206 "\377\377";
207
208 const char *newFolder32Data =
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
209 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
210 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
211 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
212 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
213 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
214 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
215 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
216 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
217 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
218 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
219 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
220 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
221 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
222 "\377\377\377\377UUU\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377"
223 "\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377>>>\377"
224 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
225 "\377\377\377\377\377\377\377\377\377\377\000\000\000\377\000\000\000\377\000\000\000\377\000"
226 "\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\377\377\377\377\377\377"
227 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
228 "\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064"
229 "\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377>>>"
230 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
231 "\377\377\377\377\377\377\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000"
232 "\000\377\000\000\000\377\000\000\000\377\000\000\000\377\377\377\377\377\377\377\377\377\377"
233 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\064\064\064\377"
234 "\064\064\064\377\204\204\204\377\204\204\204\377\204\204\204\377\204\204\204"
235 "\377\204\204\204\377\204\204\204\377yyy\377ooo\377UUU\377\064\064\064\377>>"
236 ">\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
237 "\377\377\377\000\000\000\377\000\000\000\377\363\267/\377\363\267/\377\363\267/\377\363"
238 "\267/\377\000\000\000\377\000\000\000\377\377\377\377\377\377\377\377\377\377\377\377"
239 "\377\377\377\377\377\377\377\377\377\377\377\377\377\064\064\064\377\064\064\064"
240 "\377yyy\377yyy\377yyy\377yyy\377yyy\377yyy\377yyy\377yyy\377ooo\377UUU\377"
241 "\064\064\064\377>>>\377>>>\377>>>\377>>>\377>>>\377\000\000\000\377\000\000\000\377\363"
242 "\267/\377\363\267/\377\363\267/\377\363\267/\377\000\000\000\377\000\000\000\377;;;\377"
243 ";;;\377\064\064\064\377\064\064\064\377MMM\377\377\377\377\377\064\064\064\377\064"
244 "\064\064\377ooo\377ooo\377ooo\377ooo\377ooo\377ooo\377ooo\377ooo\377ooo\377"
245 "ooo\377UUU\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064"
246 "\064\377\000\000\000\377\000\000\000\377\363\267/\377\363\267/\377\363\267/\377\363\267"
247 "/\377\000\000\000\377\000\000\000\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064"
248 "\377\064\064\064\377MMM\377\064\064\064\377\064\064\064\377ooo\377ooo\377ooo\377o"
249 "oo\377ooo\377ooo\377ooo\377ooo\377ooo\377ooo\377ooo\377ooo\377ooo\377ooo"
250 "\377ooo\377ooo\377\000\000\000\377\000\000\000\377\363\267/\377\363\267/\377\363\267"
251 "/\377\363\267/\377\000\000\000\377\000\000\000\377ooo\377ooo\377ooo\377ooo\377\064\064"
252 "\064\377\064\064\064\377\064\064\064\377\064\064\064\377ooo\377ooo\377ooo\377ooo\377"
253 "ooo\377ooo\377ooo\377ooo\377ooo\377ooo\377\000\000\000\377\000\000\000\377\000\000\000\377"
254 "\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\363\267/\377\363\267/"
255 "\377\363\267/\377\363\267/\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000"
256 "\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\064\064\064\377\064\064\064\377ooo\377o"
257 "oo\377ooo\377ooo\377ooo\377ooo\377ooo\377ooo\377ooo\377ooo\377\000\000\000\377"
258 "\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\363"
259 "\267/\377\363\267/\377\363\267/\377\363\267/\377\000\000\000\377\000\000\000\377\000\000"
260 "\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\064\064\064\377\064"
261 "\064\064\377\064\064\064\377+++\377+++\377+++\377+++\377+++\377+++\377+++\377"
262 "+++\377+++\377\000\000\000\377\000\000\000\377\363\267/\377\363\267/\377\363\267/\377"
263 "\363\267/\377\363\267/\377\363\267/\377\363\267/\377\363\267/\377\363\267"
264 "/\377\363\267/\377\363\267/\377\363\267/\377\363\267/\377\363\267/\377\363"
265 "\267/\377\363\267/\377\000\000\000\377\000\000\000\377...\377...\377...\377...\377.."
266 ".\377...\377...\377...\377...\377...\377...\377...\377\000\000\000\377\000\000\000\377"
267 "\363\267/\377\363\267/\377\363\267/\377\363\267/\377\363\267/\377\363\267"
268 "/\377\363\267/\377\363\267/\377\363\267/\377\363\267/\377\363\267/\377\363"
269 "\267/\377\363\267/\377\363\267/\377\363\267/\377\363\267/\377\000\000\000\377\000"
270 "\000\000\377...\377...\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377M"
271 "MM\377MMM\377MMM\377\000\000\000\377\000\000\000\377\363\267/\377\363\267/\377\363\267"
272 "/\377\363\267/\377\363\267/\377\363\267/\377\363\267/\377\363\267/\377\363"
273 "\267/\377\363\267/\377\363\267/\377\363\267/\377\363\267/\377\363\267/\377"
274 "\363\267/\377\363\267/\377\000\000\000\377\000\000\000\377\064\064\064\377\064\064\064\377"
275 "MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377\000"
276 "\000\000\377\000\000\000\377\363\267/\377\363\267/\377\363\267/\377\363\267/\377\363"
277 "\267/\377\363\267/\377\363\267/\377\363\267/\377\363\267/\377\363\267/\377"
278 "\363\267/\377\363\267/\377\363\267/\377\363\267/\377\363\267/\377\363\267"
279 "/\377\000\000\000\377\000\000\000\377\064\064\064\377\064\064\064\377MMM\377MMM\377MMM\377"
280 "MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377\000\000\000\377\000\000\000\377\000\000"
281 "\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\363\267/\377\363"
282 "\267/\377\363\267/\377\363\267/\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377"
283 "\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\064\064\064\377\064\064\064\377MMM\377"
284 "MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377\000\000\000\377"
285 "\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\363"
286 "\267/\377\363\267/\377\363\267/\377\363\267/\377\000\000\000\377\000\000\000\377\000\000"
287 "\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\064\064\064\377\064"
288 "\064\064\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377"
289 "MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377\000\000\000\377\000\000\000\377\363"
290 "\267/\377\363\267/\377\363\267/\377\363\267/\377\000\000\000\377\000\000\000\377MMM\377"
291 "MMM\377MMM\377MMM\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377"
292 "MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MM"
293 "M\377MMM\377MMM\377MMM\377MMM\377MMM\377\000\000\000\377\000\000\000\377\363\267/\377"
294 "\363\267/\377\363\267/\377\363\267/\377\000\000\000\377\000\000\000\377MMM\377MMM\377"
295 "MMM\377MMM\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377MMM\377"
296 "MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MM"
297 "M\377MMM\377MMM\377MMM\377MMM\377\000\000\000\377\000\000\000\377\363\267/\377\363\267"
298 "/\377\363\267/\377\363\267/\377\000\000\000\377\000\000\000\377MMM\377MMM\377MMM\377"
299 "MMM\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377MMM\377MMM\377"
300 "MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MM"
301 "M\377MMM\377MMM\377MMM\377\000\000\000\377\000\000\000\377\363\267/\377\363\267/\377"
302 "\363\267/\377\363\267/\377\000\000\000\377\000\000\000\377MMM\377MMM\377MMM\377MMM\377"
303 "\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377MMM\377MMM\377MMM\377"
304 "MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MM"
305 "M\377MMM\377MMM\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000"
306 "\000\377\000\000\000\377\000\000\000\377MMM\377MMM\377MMM\377MMM\377\064\064\064\377\064\064"
307 "\064\377\064\064\064\377\064\064\064\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377"
308 "MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377\000"
309 "\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000"
310 "\000\377MMM\377MMM\377MMM\377MMM\377\064\064\064\377\064\064\064\377\064\064\064\377"
311 "\064\064\064\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM"
312 "\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377"
313 "MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377\064\064\064"
314 "\377\064\064\064\377\064\064\064\377\064\064\064\377MMM\377MMM\377MMM\377MMM\377M"
315 "MM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM"
316 "\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377"
317 "MMM\377MMM\377MMM\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377"
318 "MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MM"
319 "M\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377"
320 "MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377\064\064\064\377\064\064\064\377"
321 "\064\064\064\377\064\064\064\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377"
322 "MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MM"
323 "M\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377"
324 "\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377MMM\377MMM\377MMM\377"
325 "MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MM"
326 "M\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377HHH\377HHH\377"
327 "HHH\377HHH\377HHH\377HHH\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064"
328 "\064\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377MMM\377HHH\377HH"
329 "H\377HHH\377HHH\377HHH\377HHH\377HHH\377HHH\377HHH\377HHH\377FFF\377FFF\377"
330 "FFF\377FFF\377FFF\377FFF\377FFF\377FFF\377FFF\377FFF\377\064\064\064\377\064"
331 "\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377"
332 "\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064"
333 "\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377\064"
334 "\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377"
335 "\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064"
336 "\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377UUU\377\064\064\064"
337 "\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377\064"
338 "\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377"
339 "\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064"
340 "\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377\064"
341 "\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377\064\064\064\377"
342 "\064\064\064\377UUU\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
343 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
344 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
345 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
346 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
347 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
348 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
349 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
350 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
351 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
352 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
353 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
354 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
355 "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
356 "\377\377\377\377\377\377\377\377\377";
357
358 typedef struct FileDialogData FileDialogData;
359
360 static void FileListDetailSelect(FileDialogData *fsb,
const char *item);
361 static void FileListSelect(FileDialogData *fsb,
const char *item);
362 static void FileIconViewSelect(FileDialogData *fsb,
const char *item);
363
364 static void FileSelect(FileDialogData *fsb,
const char *item);
365
366 static void select_view(FileDialogData *data);
367
368 static void filedialog_update_dir(FileDialogData *data,
char *path);
369
370 static void filedialog_ok(Widget w, FileDialogData *data, XtPointer d);
371
372
373
374
375 static int get_shift(
unsigned long mask) {
376 if(mask ==
0) {
377 return 0;
378 }
379
380 int shift =
0;
381 while((mask &
1L) ==
0) {
382 shift++;
383 mask >>=
1;
384 }
385 return shift;
386 }
387
388
389
390
391 static int get_mask_len(
unsigned long mask) {
392 if(mask ==
0) {
393 return 0;
394 }
395
396 while((mask &
1L) ==
0) {
397 mask >>=
1;
398 }
399 int len =
0;
400 while((mask &
1L) ==
1) {
401 len++;
402 mask >>=
1;
403 }
404 return len;
405 }
406
407
408
409
410 static void create_image(Display *dp, Visual *visual,
int depth, Pixmap pix,
const char *data,
int wh) {
411
412 size_t imglen = wh*wh*
4;
413 char *imgdata = malloc(imglen);
414
415
416 int red_shift = get_shift(visual->red_mask);
417 int green_shift = get_shift(visual->green_mask);
418 int blue_shift = get_shift(visual->blue_mask);
419
420 uint32_t *src = (
uint32_t*)data;
421 uint32_t *dst = (
uint32_t*)imgdata;
422
423 uint32_t pixel_init =
UINT32_MAX ^ (visual->red_mask ^ visual->green_mask ^ visual->blue_mask);
424
425
426 size_t len = wh*wh;
427 for(
int i=
0;i<len;i++) {
428 uint32_t pixel = src[i];
429 #if defined(__sparc) || defined(__sparc__)
430
431
432 uint8_t blue = (pixel & 0xFF00) >>
8;
433 uint8_t green = (pixel & 0xFF0000) >>
16;
434 uint8_t red = (pixel & 0xFF000000) >>
24;
435 #else
436
437 uint8_t red = pixel & 0xFF;
438 uint8_t green = (pixel & 0xFF00) >>
8;
439 uint8_t blue = (pixel & 0xFF0000) >>
16;
440 #endif
441
442 if(pixel ==
UINT32_MAX) {
443 red = bgColor.red;
444 green = bgColor.green;
445 blue = bgColor.blue;
446 }
447
448 uint32_t out = pixel_init;
449 out ^= (red << red_shift);
450 out ^= (green << green_shift);
451 out ^= (blue << blue_shift);
452 dst[i] = out;
453 }
454
455
456 XImage *img = XCreateImage(dp, visual, depth, ZPixmap,
0, imgdata, wh, wh,
32,
0);
457
458 XGCValues gcval;
459 gcval.graphics_exposures =
0;
460 unsigned long valuemask = GCGraphicsExposures;
461 GC gc = XCreateGC(dp, newFolderIcon16, valuemask, &gcval);
462
463 XPutImage(dp, pix, gc, img,
0,
0,
0,
0, wh, wh);
464
465 XDestroyImage(img);
466 XFreeGC(dp, gc);
467 }
468
469 static void initPixmaps(Display *dp, Drawable d, Screen *screen,
int depth)
470 {
471
472 Visual *visual =
NULL;
473 for(
int i=
0;i<screen->ndepths;i++) {
474 Depth d = screen->depths[i];
475 if(d.depth == depth) {
476 for(
int v=
0;v<d.nvisuals;v++) {
477 Visual *vs = &d.visuals[v];
478 if(get_mask_len(vs->red_mask) ==
8) {
479 visual = vs;
480 break;
481 }
482 }
483 }
484 }
485
486 if(!visual) {
487
488 fprintf(stderr,
"can''t use images with this visual\n");
489 pixmaps_initialized =
1;
490 pixmaps_error =
1;
491 return;
492 }
493
494
495 newFolderIcon16 = XCreatePixmap(dp, d,
16,
16, depth);
496 if(newFolderIcon16 == BadValue) {
497 fprintf(stderr,
"failed to create newFolderIcon16 pixmap\n");
498 pixmaps_error =
1;
499 }
else {
500 create_image(dp, visual, depth, newFolderIcon16, newFolder16Data,
16);
501 }
502
503 newFolderIcon24 = XCreatePixmap(dp, d,
24,
24, depth);
504 if(newFolderIcon24 == BadValue) {
505 fprintf(stderr,
"failed to create newFolderIcon24 pixmap\n");
506 pixmaps_error =
1;
507 }
else {
508 create_image(dp, visual, depth, newFolderIcon24, newFolder24Data,
24);
509 }
510
511 newFolderIcon32 = XCreatePixmap(dp, d,
32,
32, depth);
512 if(newFolderIcon32 == BadValue) {
513 fprintf(stderr,
"failed to create newFolderIcon32 pixmap\n");
514 pixmaps_error =
1;
515 }
else {
516 create_image(dp, visual, depth, newFolderIcon32, newFolder32Data,
32);
517 }
518
519 pixmaps_initialized =
1;
520 }
521
522
523
524
525 typedef void(*updatedir_callback)(
void*,
char*);
526
527 typedef struct PathBar {
528 Widget widget;
529 Widget textfield;
530
531 Widget focus_widget;
532
533 Widget left;
534 Widget right;
535 Dimension lw;
536 Dimension rw;
537
538 int shift;
539
540 Widget *pathSegments;
541 size_t numSegments;
542 size_t segmentAlloc;
543
544 char *path;
545 int selection;
546 Boolean input;
547
548 int focus;
549
550 updatedir_callback updateDir;
551 void *updateDirData;
552 } PathBar;
553
554 void PathBarSetPath(PathBar *bar,
char *path);
555
556 void pathbar_resize(Widget w, PathBar *p, XtPointer d)
557 {
558 Dimension width, height;
559 XtVaGetValues(w, XmNwidth, &width, XmNheight, &height,
NULL);
560
561 Dimension *segW = NEditCalloc(p->numSegments,
sizeof(Dimension));
562
563 Dimension maxHeight =
0;
564
565
566 Dimension pathWidth =
0;
567 for(
int i=
0;i<p->numSegments;i++) {
568 Dimension segWidth;
569 Dimension segHeight;
570 XtVaGetValues(p->pathSegments[i], XmNwidth, &segWidth, XmNheight, &segHeight,
NULL);
571 segW[i] = segWidth;
572 pathWidth += segWidth;
573 if(segHeight > maxHeight) {
574 maxHeight = segHeight;
575 }
576 }
577 Dimension tfHeight;
578 XtVaGetValues(p->textfield, XmNheight, &tfHeight,
NULL);
579 if(tfHeight > maxHeight) {
580 maxHeight = tfHeight;
581 }
582
583 Boolean arrows = False;
584 if(pathWidth +
10 > width) {
585 arrows = True;
586 pathWidth += p->lw + p->rw;
587 }
588
589
590 int start =
0;
591 if(arrows) {
592 Dimension vis = p->lw+p->rw;
593 for(
int i=p->numSegments;i>
0;i--) {
594 Dimension segWidth = segW[i-
1];
595 if(vis + segWidth +
10 > width) {
596 start = i;
597 arrows = True;
598 break;
599 }
600 vis += segWidth;
601 }
602 }
else {
603 p->shift =
0;
604 }
605
606 int leftShift =
0;
607 if(p->shift <
0) {
608 if(start + p->shift <
0) {
609 leftShift = start;
610 start =
0;
611 p->shift = -leftShift;
612 }
else {
613 leftShift = -p->shift;
614 start += p->shift;
615 }
616 }
617
618 int x =
0;
619 if(arrows) {
620 XtManageChild(p->left);
621 XtManageChild(p->right);
622 x = p->lw;
623 }
else {
624 XtUnmanageChild(p->left);
625 XtUnmanageChild(p->right);
626 }
627
628 for(
int i=
0;i<p->numSegments;i++) {
629 if(i >= start && i < p->numSegments - leftShift && !p->input) {
630 XtVaSetValues(p->pathSegments[i], XmNx, x, XmNy,
0, XmNheight, maxHeight,
NULL);
631 x += segW[i];
632 XtManageChild(p->pathSegments[i]);
633 }
else {
634 XtUnmanageChild(p->pathSegments[i]);
635 }
636 }
637
638 if(arrows) {
639 XtVaSetValues(p->left, XmNx,
0, XmNy,
0, XmNheight, maxHeight,
NULL);
640 XtVaSetValues(p->right, XmNx, x, XmNy,
0, XmNheight, maxHeight,
NULL);
641 }
642
643 NEditFree(segW);
644
645 Dimension rw, rh;
646 XtMakeResizeRequest(w, width, maxHeight, &rw, &rh);
647
648 XtVaSetValues(p->textfield, XmNwidth, rw, XmNheight, rh,
NULL);
649 }
650
651 static void pathbarActivateTF(PathBar *p)
652 {
653 XtUnmanageChild(p->left);
654 XtUnmanageChild(p->right);
655 XNETextSetSelection(p->textfield,
0, XNETextGetLastPosition(p->textfield),
0);
656 XtManageChild(p->textfield);
657 p->input =
1;
658
659 XmProcessTraversal(p->textfield, XmTRAVERSE_CURRENT);
660
661 pathbar_resize(p->widget, p,
NULL);
662 }
663
664 void PathBarActivateTextfield(PathBar *p)
665 {
666 p->focus =
1;
667 pathbarActivateTF(p);
668 }
669
670 void pathbar_input(Widget w, PathBar *p, XtPointer c)
671 {
672 XmDrawingAreaCallbackStruct *cbs = (XmDrawingAreaCallbackStruct*)c;
673 XEvent *xevent = cbs->event;
674
675 if (cbs->reason == XmCR_INPUT) {
676 if (xevent->xany.type == ButtonPress) {
677 p->focus =
0;
678 pathbarActivateTF(p);
679 }
680 }
681 }
682
683 void pathbar_losingfocus(Widget w, PathBar *p, XtPointer c)
684 {
685 if(--p->focus <
0) {
686 p->input = False;
687 XtUnmanageChild(p->textfield);
688 }
689 }
690
691 void pathbar_pathinput(Widget w, PathBar *p, XtPointer d)
692 {
693 char *newpath = XNETextGetString(p->textfield);
694 if(newpath) {
695 if(newpath[
0] ==
'~') {
696 char *p = newpath+
1;
697 char *cp = ConcatPath(GetHomeDir(), p);
698 XtFree(newpath);
699 newpath = cp;
700 }
else if(newpath[
0] !=
'/') {
701 char *cp = ConcatPath(GetCurrentDir(), newpath);
702 XtFree(newpath);
703 newpath = cp;
704 }
705
706
707 PathBarSetPath(p, newpath);
708 if(p->updateDir) {
709 p->updateDir(p->updateDirData, newpath);
710 }
711 XtFree(newpath);
712
713
714 XtUnmanageChild(p->textfield);
715 pathbar_resize(p->widget, p,
NULL);
716
717 if(p->focus_widget) {
718 XmProcessTraversal(p->focus_widget, XmTRAVERSE_CURRENT);
719 }
720 }
721 }
722
723 void pathbar_shift_left(Widget w, PathBar *p, XtPointer d)
724 {
725 p->shift--;
726 pathbar_resize(p->widget, p,
NULL);
727 }
728
729 void pathbar_shift_right(Widget w, PathBar *p, XtPointer d)
730 {
731 if(p->shift <
0) {
732 p->shift++;
733 }
734 pathbar_resize(p->widget, p,
NULL);
735 }
736
737 static void pathTextEH(Widget widget, XtPointer data, XEvent *event, Boolean *dispatch) {
738 PathBar *pb = data;
739 if(event->type == KeyReleaseMask) {
740 if(event->xkey.keycode ==
9) {
741 XtUnmanageChild(pb->textfield);
742 pathbar_resize(pb->widget, pb,
NULL);
743 *dispatch = False;
744 }
else if(event->xkey.keycode ==
36) {
745 pathbar_pathinput(pb->textfield, pb,
NULL);
746 *dispatch = False;
747 }
748 }
749 }
750
751 PathBar* CreatePathBar(Widget parent, ArgList args,
int n)
752 {
753 PathBar *bar = NEditMalloc(
sizeof(PathBar));
754 bar->path =
NULL;
755 bar->updateDir =
NULL;
756 bar->updateDirData =
NULL;
757
758 bar->focus_widget =
NULL;
759
760 bar->shift =
0;
761
762 XtSetArg(args[n], XmNmarginWidth,
0); n++;
763 XtSetArg(args[n], XmNmarginHeight,
0); n++;
764 bar->widget = XmCreateDrawingArea(parent,
"pathbar", args, n);
765 XtAddCallback(
766 bar->widget,
767 XmNresizeCallback,
768 (XtCallbackProc)pathbar_resize,
769 bar);
770 XtAddCallback(
771 bar->widget,
772 XmNinputCallback,
773 (XtCallbackProc)pathbar_input,
774 bar);
775
776 Arg a[
4];
777 XtSetArg(a[
0], XmNshadowThickness,
0);
778 XtSetArg(a[
1], XmNx,
0);
779 XtSetArg(a[
2], XmNy,
0);
780 bar->textfield = XNECreateText(bar->widget,
"pbtext", a,
3);
781 bar->input =
0;
782 XtAddCallback(
783 bar->textfield,
784 XmNlosingFocusCallback,
785 (XtCallbackProc)pathbar_losingfocus,
786 bar);
787 XtAddCallback(bar->textfield, XmNactivateCallback,
788 (XtCallbackProc)pathbar_pathinput, bar);
789 XtAddEventHandler(bar->textfield, KeyPressMask | KeyReleaseMask,
FALSE, pathTextEH, bar);
790
791 XtSetArg(a[
0], XmNarrowDirection, XmARROW_LEFT);
792 bar->left = XmCreateArrowButton(bar->widget,
"pbbutton", a,
1);
793 XtSetArg(a[
0], XmNarrowDirection, XmARROW_RIGHT);
794 bar->right = XmCreateArrowButton(bar->widget,
"pbbutton", a,
1);
795 XtAddCallback(
796 bar->left,
797 XmNactivateCallback,
798 (XtCallbackProc)pathbar_shift_left,
799 bar);
800 XtAddCallback(
801 bar->right,
802 XmNactivateCallback,
803 (XtCallbackProc)pathbar_shift_right,
804 bar);
805
806 Pixel bg;
807 XtVaGetValues(bar->textfield, XmNbackground, &bg,
NULL);
808 XtVaSetValues(bar->widget, XmNbackground, bg,
NULL);
809
810 XtManageChild(bar->left);
811 XtManageChild(bar->right);
812
813 XtVaGetValues(bar->left, XmNwidth, &bar->lw,
NULL);
814 XtVaGetValues(bar->right, XmNwidth, &bar->rw,
NULL);
815
816 bar->segmentAlloc =
16;
817 bar->numSegments =
0;
818 bar->pathSegments = NEditCalloc(
16,
sizeof(Widget));
819
820 bar->selection =
0;
821
822 return bar;
823 }
824
825 void PathBarChangeDir(Widget w, PathBar *bar, XtPointer c)
826 {
827 XmToggleButtonSetState(bar->pathSegments[bar->selection], False, False);
828
829 for(
int i=
0;i<bar->numSegments;i++) {
830 if(bar->pathSegments[i] == w) {
831 bar->selection = i;
832 XmToggleButtonSetState(w, True, False);
833 break;
834 }
835 }
836
837 int plen = strlen(bar->path);
838 int countSeg =
0;
839 for(
int i=
0;i<=plen;i++) {
840 char c = bar->path[i];
841 if(c ==
'/' || c ==
'\0') {
842 if(countSeg == bar->selection) {
843 char *dir = NEditMalloc(i+
2);
844 memcpy(dir, bar->path, i+
1);
845 dir[i+
1] =
'\0';
846 if(bar->updateDir) {
847 bar->updateDir(bar->updateDirData, dir);
848 }
849 NEditFree(dir);
850 }
851 countSeg++;
852 }
853 }
854 }
855
856 void PathBarSetPath(PathBar *bar,
char *path)
857 {
858 if(bar->path) {
859 NEditFree(bar->path);
860 }
861 bar->path = NEditStrdup(path);
862
863 for(
int i=
0;i<bar->numSegments;i++) {
864 XtDestroyWidget(bar->pathSegments[i]);
865 }
866 XtUnmanageChild(bar->textfield);
867 XtManageChild(bar->left);
868 XtManageChild(bar->right);
869 bar->input = False;
870
871 Arg args[
4];
872 XmString str;
873
874 bar->numSegments =
0;
875
876 int i=
0;
877 if(path[
0] ==
'/') {
878 str = XmStringCreateLocalized(
"/");
879 XtSetArg(args[
0], XmNlabelString, str);
880 XtSetArg(args[
1], XmNfillOnSelect, True);
881 XtSetArg(args[
2], XmNindicatorOn, False);
882 bar->pathSegments[
0] = XmCreateToggleButton(
883 bar->widget,
"pbbutton", args,
3);
884 XtAddCallback(
885 bar->pathSegments[
0],
886 XmNvalueChangedCallback,
887 (XtCallbackProc)PathBarChangeDir,
888 bar);
889 XmStringFree(str);
890 bar->numSegments++;
891 i++;
892 }
893
894 int len = strlen(path);
895 int begin = i;
896 for(;i<=len;i++) {
897 char c = path[i];
898 if((c ==
'/' || c ==
'\0') && i > begin) {
899 char *segStr = NEditMalloc(i - begin +
1);
900 memcpy(segStr, path+begin, i-begin);
901 segStr[i-begin] =
'\0';
902 begin = i+
1;
903
904 str = XmStringCreateLocalized(segStr);
905 NEditFree(segStr);
906 XtSetArg(args[
0], XmNlabelString, str);
907 XtSetArg(args[
1], XmNfillOnSelect, True);
908 XtSetArg(args[
2], XmNindicatorOn, False);
909 Widget button = XmCreateToggleButton(bar->widget,
"pbbutton", args,
3);
910 XtAddCallback(
911 button,
912 XmNvalueChangedCallback,
913 (XtCallbackProc)PathBarChangeDir,
914 bar);
915 XmStringFree(str);
916
917 if(bar->numSegments >= bar->segmentAlloc) {
918 bar->segmentAlloc +=
8;
919 bar->pathSegments = realloc(bar->pathSegments, bar->segmentAlloc *
sizeof(Widget));
920 }
921
922 bar->pathSegments[bar->numSegments++] = button;
923 }
924 }
925
926 bar->selection = bar->numSegments-
1;
927 XmToggleButtonSetState(bar->pathSegments[bar->selection], True, False);
928
929 XNETextSetString(bar->textfield, path);
930 XNETextSetInsertionPosition(bar->textfield, XNETextGetLastPosition(bar->textfield));
931
932 pathbar_resize(bar->widget, bar,
NULL);
933 }
934
935 void PathBarDestroy(PathBar *pathbar) {
936 if(pathbar->path) {
937 NEditFree(pathbar->path);
938 }
939 NEditFree(pathbar->pathSegments);
940 NEditFree(pathbar);
941 }
942
943
944
945
946
947 typedef struct FileElm FileElm;
948 struct FileElm {
949 char *path;
950 int isDirectory;
951 uint64_t size;
952 time_t lastModified;
953 };
954
955 struct FileDialogData {
956 Widget shell;
957
958 char *file_path;
959
960 Widget path;
961 PathBar *pathBar;
962 Widget filter;
963
964 int selectedview;
965
966
967 Widget listform;
968 Widget dirlist;
969 Widget filelist;
970 Widget filelistcontainer;
971
972
973 Widget grid;
974 Widget gridcontainer;
975
976 Widget okBtn;
977 Widget name;
978 Widget wrap;
979 Widget unixFormat;
980 Widget dosFormat;
981 Widget macFormat;
982 Widget encoding;
983 Widget iofilter;
984 Widget bom;
985 Widget xattr;
986
987 FileElm *dirs;
988 FileElm *files;
989 int dircount;
990 int filecount;
991 int maxnamelen;
992
993 int gridRealized;
994
995 char *currentPath;
996 char *selectedPath;
997 int selIsDir;
998 int showHidden;
999
1000 IOFilter **filters;
1001 size_t nfilters;
1002 IOFilter *selected_filter;
1003
1004 int type;
1005
1006 int end;
1007 int status;
1008 };
1009
1010 static void filedialog_cancel(Widget w, FileDialogData *data, XtPointer d)
1011 {
1012 data->end =
1;
1013 data->status =
FILEDIALOG_CANCEL;
1014 }
1015
1016 static void cleanupLists(FileDialogData *data)
1017 {
1018 XmListDeleteAllItems(data->dirlist);
1019 XmListDeleteAllItems(data->filelist);
1020 }
1021
1022 static void filedialog_check_iofilters(FileDialogData *data,
const char *path)
1023 {
1024 if(!path || !data->iofilter) {
1025 return;
1026 }
1027
1028 for(
int i=
0;i<data->nfilters;i++) {
1029 if(data->filters[i]->ec_pattern) {
1030 if(!ec_glob(data->filters[i]->ec_pattern, path)) {
1031 XtVaSetValues(data->iofilter, XmNselectedPosition, i+
1,
NULL);
1032 return;
1033 }
1034 }
1035 }
1036
1037 XtVaSetValues(data->iofilter, XmNselectedPosition,
0,
NULL);
1038 }
1039
1040
1041
1042
1043
1044
1045
1046 static int file_cmp_field =
0;
1047
1048
1049
1050
1051 static int file_cmp_order =
1;
1052
1053 static int filecmp(
const void *f1,
const void *f2)
1054 {
1055 const FileElm *file1 = f1;
1056 const FileElm *file2 = f2;
1057 if(file1->isDirectory != file2->isDirectory) {
1058 return file1->isDirectory < file2->isDirectory;
1059 }
1060
1061 int cmp_field = file_cmp_field;
1062 int cmp_order = file_cmp_order;
1063 if(file1->isDirectory) {
1064 cmp_field =
0;
1065 cmp_order =
1;
1066 }
1067
1068 int ret =
0;
1069 switch(cmp_field) {
1070 case 0: {
1071 ret = strcmp(FileName(file1->path), FileName(file2->path));
1072 break;
1073 }
1074 case 1: {
1075 if(file1->size < file2->size) {
1076 ret = -
1;
1077 }
else if(file1->size == file2->size) {
1078 ret =
0;
1079 }
else {
1080 ret =
1;
1081 }
1082 break;
1083 }
1084 case 2: {
1085 if(file1->lastModified < file2->lastModified) {
1086 ret = -
1;
1087 }
else if(file1->lastModified == file2->lastModified) {
1088 ret =
0;
1089 }
else {
1090 ret =
1;
1091 }
1092 break;
1093 }
1094 }
1095
1096 return ret * cmp_order;
1097 }
1098
1099 typedef void(*ViewUpdateFunc)(FileDialogData*,FileElm*,FileElm*,
int,
int,
int);
1100
1101
1102 static void filelistwidget_add(Widget w,
int showHidden,
char *filter, FileElm *ls,
int count)
1103 {
1104 if(count >
0) {
1105 XmStringTable items = NEditCalloc(count,
sizeof(XmString));
1106 int i =
0;
1107
1108 for(
int j=
0;j<count;j++) {
1109 FileElm *e = &ls[j];
1110
1111 char *name = FileName(e->path);
1112 if((!showHidden && name[
0] ==
'.') || fnmatch(filter, name,
0)) {
1113 continue;
1114 }
1115
1116 items[i] = XmStringCreateLocalized(name);
1117 i++;
1118 }
1119 XmListAddItems(w, items, i,
0);
1120 for(
int i=
0;i<count;i++) {
1121 XmStringFree(items[i]);
1122 }
1123 NEditFree(items);
1124 }
1125 }
1126
1127
1128 static void filedialog_update_lists(
1129 FileDialogData *data,
1130 FileElm *dirs,
1131 FileElm *files,
1132 int dircount,
1133 int filecount,
1134 int maxnamelen)
1135 {
1136 char *filter = XNETextGetString(data->filter);
1137 char *filterStr = filter;
1138 if(!filter || strlen(filter) ==
0) {
1139 filterStr =
"*";
1140 }
1141
1142 filelistwidget_add(data->dirlist, data->showHidden,
"*", dirs, dircount);
1143 filelistwidget_add(data->filelist, data->showHidden, filterStr, files, filecount);
1144
1145 if(filter) {
1146 XtFree(filter);
1147 }
1148 }
1149
1150
1151
1152
1153 static char* size_str(FileElm *f) {
1154 char *str = malloc(
16);
1155 uint64_t size = f->size;
1156
1157 if(f->isDirectory) {
1158 str[
0] =
'\0';
1159 }
else if(size < 0x400) {
1160 snprintf(str,
16,
"%d bytes", (
int)size);
1161 }
else if(size < 0x100000) {
1162 float s = (
float)size/0x400;
1163 int diff = (s*
100 - (
int)s*
100);
1164 if(diff >
90) {
1165 diff =
0;
1166 s +=
0.10f;
1167 }
1168 if(size < 0x2800 && diff !=
0) {
1169
1170 snprintf(str,
16,
"%.1f " KB_SUFFIX, s);
1171 }
else {
1172 snprintf(str,
16,
"%.0f " KB_SUFFIX, s);
1173 }
1174 }
else if(size < 0x40000000) {
1175 float s = (
float)size/0x100000;
1176 int diff = (s*
100 - (
int)s*
100);
1177 if(diff >
90) {
1178 diff =
0;
1179 s +=
0.10f;
1180 }
1181 if(size < 0xa00000 && diff !=
0) {
1182
1183 snprintf(str,
16,
"%.1f " MB_SUFFIX, s);
1184 }
else {
1185 size /= 0x100000;
1186 snprintf(str,
16,
"%.0f " MB_SUFFIX, s);
1187 }
1188 }
else if(size < 0x1000000000ULL) {
1189 float s = (
float)size/0x40000000;
1190 int diff = (s*
100 - (
int)s*
100);
1191 if(diff >
90) {
1192 diff =
0;
1193 s +=
0.10f;
1194 }
1195 if(size < 0x280000000 && diff !=
0) {
1196
1197 snprintf(str,
16,
"%.1f " GB_SUFFIX, s);
1198 }
else {
1199 size /= 0x40000000;
1200 snprintf(str,
16,
"%.0f " GB_SUFFIX, s);
1201 }
1202 }
else {
1203 size /=
1024;
1204 float s = (
float)size/0x40000000;
1205 int diff = (s*
100 - (
int)s*
100);
1206 if(diff >
90) {
1207 diff =
0;
1208 s +=
0.10f;
1209 }
1210 if(size < 0x280000000 && diff !=
0) {
1211
1212 snprintf(str,
16,
"%.1f " TB_SUFFIX, s);
1213 }
else {
1214 size /= 0x40000000;
1215 snprintf(str,
16,
"%.0f " TB_SUFFIX, s);
1216 }
1217 }
1218 return str;
1219 }
1220
1221 static char* date_str(
time_t tm) {
1222 struct tm t;
1223 struct tm n;
1224 time_t now = time(
NULL);
1225
1226 localtime_r(&tm, &t);
1227 localtime_r(&now, &n);
1228
1229 char *str = malloc(
16);
1230 if(t.tm_year == n.tm_year) {
1231 strftime(str,
16,
DATE_FORMAT_SAME_YEAR, &t);
1232 }
else {
1233 strftime(str,
16,
DATE_FORMAT_OTHER_YEAR, &t);
1234 }
1235 return str;
1236 }
1237
1238 static void filegridwidget_add(Widget grid,
int showHidden,
char *filter, FileElm *ls,
int count,
int maxWidth)
1239 {
1240 XmLGridAddRows(grid, XmCONTENT,
1, count);
1241
1242 int row =
0;
1243 for(
int i=
0;i<count;i++) {
1244 FileElm *e = &ls[i];
1245
1246 char *name = FileName(e->path);
1247 if((!showHidden && name[
0] ==
'.') || (!e->isDirectory && fnmatch(filter, name,
0))) {
1248 continue;
1249 }
1250
1251
1252 XmString str = XmStringCreateLocalized(name);
1253 XtVaSetValues(grid,
1254 XmNcolumn,
0,
1255 XmNrow, row,
1256 XmNcellString, str,
NULL);
1257 XmStringFree(str);
1258
1259 char *szbuf = size_str(e);
1260 str = XmStringCreateLocalized(szbuf);
1261 XtVaSetValues(grid,
1262 XmNcolumn,
1,
1263 XmNrow, row,
1264 XmNcellString, str,
NULL);
1265 free(szbuf);
1266 XmStringFree(str);
1267
1268 char *datebuf = date_str(e->lastModified);
1269 str = XmStringCreateLocalized(datebuf);
1270 XtVaSetValues(grid,
1271 XmNcolumn,
2,
1272 XmNrow, row,
1273 XmNcellString, str,
NULL);
1274 free(datebuf);
1275 XmStringFree(str);
1276
1277 XtVaSetValues(grid, XmNrow, row, XmNrowUserData, e,
NULL);
1278 row++;
1279 }
1280
1281
1282 if(count > row) {
1283 XmLGridDeleteRows(grid, XmCONTENT, row, count-row);
1284 }
1285
1286 if(maxWidth <
16) {
1287 maxWidth =
16;
1288 }
1289
1290 XtVaSetValues(grid,
1291 XmNcolumnRangeStart,
0,
1292 XmNcolumnRangeEnd,
0,
1293 XmNcolumnWidth, maxWidth,
1294 XmNcellAlignment, XmALIGNMENT_LEFT,
1295 XmNcolumnSizePolicy, XmVARIABLE,
1296 NULL);
1297 XtVaSetValues(grid,
1298 XmNcolumnRangeStart,
1,
1299 XmNcolumnRangeEnd,
1,
1300 XmNcolumnWidth,
9,
1301 XmNcellAlignment, XmALIGNMENT_LEFT,
1302 XmNcolumnSizePolicy, XmVARIABLE,
1303 NULL);
1304 XtVaSetValues(grid,
1305 XmNcolumnRangeStart,
2,
1306 XmNcolumnRangeEnd,
2,
1307 XmNcolumnWidth,
16,
1308 XmNcellAlignment, XmALIGNMENT_RIGHT,
1309 XmNcolumnSizePolicy, XmVARIABLE,
1310 NULL);
1311
1312 XmLGridColumn column0 = XmLGridGetColumn(grid, XmCONTENT,
1);
1313 XmLGridColumn column1 = XmLGridGetColumn(grid, XmCONTENT,
1);
1314 XmLGridColumn column2 = XmLGridGetColumn(grid, XmCONTENT,
2);
1315
1316 Dimension col0Width = XmLGridColumnWidthInPixels(column0);
1317 Dimension col1Width = XmLGridColumnWidthInPixels(column1);
1318 Dimension col2Width = XmLGridColumnWidthInPixels(column2);
1319
1320 Dimension totalWidth = col0Width + col1Width + col2Width;
1321
1322 Dimension gridWidth =
0;
1323 Dimension gridShadow =
0;
1324 XtVaGetValues(grid, XmNwidth, &gridWidth, XmNshadowThickness, &gridShadow,
NULL);
1325
1326 Dimension widthDiff = gridWidth - totalWidth - gridShadow - gridShadow;
1327
1328 if(gridWidth > totalWidth) {
1329 XtVaSetValues(grid,
1330 XmNcolumnRangeStart,
0,
1331 XmNcolumnRangeEnd,
0,
1332 XmNcolumnWidth, col0Width + widthDiff - XmLGridVSBWidth(grid) -
2,
1333 XmNcolumnSizePolicy, XmCONSTANT,
1334 NULL);
1335 }
1336 }
1337
1338 static void filedialog_update_grid(
1339 FileDialogData *data,
1340 FileElm *dirs,
1341 FileElm *files,
1342 int dircount,
1343 int filecount,
1344 int maxnamelen)
1345 {
1346 char *filter = XNETextGetString(data->filter);
1347 char *filterStr = filter;
1348 if(!filter || strlen(filter) ==
0) {
1349 filterStr =
"*";
1350 }
1351
1352
1353 filelistwidget_add(data->dirlist, data->showHidden,
"*", dirs, dircount);
1354
1355 filegridwidget_add(data->grid, data->showHidden, filterStr, files, filecount, maxnamelen);
1356
1357 if(filter) {
1358 XtFree(filter);
1359 }
1360 }
1361
1362 static void cleanupGrid(FileDialogData *data)
1363 {
1364
1365 XmListDeleteAllItems(data->dirlist);
1366
1367
1368 Cardinal rows =
0;
1369 XtVaGetValues(data->grid, XmNrows, &rows,
NULL);
1370 XmLGridDeleteRows(data->grid, XmCONTENT,
0, rows);
1371 }
1372
1373
1374 static void free_files(FileElm *ls,
int count)
1375 {
1376 for(
int i=
0;i<count;i++) {
1377 if(ls[i].path) {
1378 free(ls[i].path);
1379 }
1380 }
1381 free(ls);
1382 }
1383
1384 static void filedialog_cleanup_filedata(FileDialogData *data)
1385 {
1386 if(data->dirs) {
1387 free_files(data->dirs, data->dircount);
1388 }
1389 if(data->files) {
1390 free_files(data->files, data->filecount);
1391 }
1392 data->dirs =
NULL;
1393 data->files =
NULL;
1394 data->dircount =
0;
1395 data->filecount =
0;
1396 data->maxnamelen =
0;
1397 }
1398
1399
1400
1401 static void FileListDetailSelect(FileDialogData *fsb,
const char *item) {
1402 int numRows =
0;
1403 XtVaGetValues(fsb->grid, XmNrows, &numRows,
NULL);
1404
1405 XmLGridColumn col = XmLGridGetColumn(fsb->grid, XmCONTENT,
0);
1406 for(
int i=
0;i<numRows;i++) {
1407 XmLGridRow row = XmLGridGetRow(fsb->grid, XmCONTENT, i);
1408 FileElm *elm =
NULL;
1409 XtVaGetValues(fsb->grid, XmNrowPtr, row, XmNcolumnPtr, col, XmNrowUserData, &elm,
NULL);
1410 if(elm) {
1411 if(!strcmp(item, FileName(elm->path))) {
1412 XmLGridSelectRow(fsb->grid, i, False);
1413 XmLGridFocusAndShowRow(fsb->grid, i+
1);
1414 break;
1415 }
1416 }
1417 }
1418 }
1419
1420 static void FileListSelect(FileDialogData *fsb,
const char *item) {
1421 int numItems =
0;
1422 XmStringTable items =
NULL;
1423 XtVaGetValues(fsb->filelist, XmNitemCount, &numItems, XmNitems, &items,
NULL);
1424
1425 for(
int i=
0;i<numItems;i++) {
1426 char *str =
NULL;
1427 XmStringGetLtoR(items[i], XmFONTLIST_DEFAULT_TAG, &str);
1428 if(!strcmp(str, item)) {
1429 XmListSelectPos(fsb->filelist, i+
1, False);
1430 break;
1431 }
1432 XtFree(str);
1433 }
1434 }
1435
1436 static void FileIconViewSelect(FileDialogData *fsb,
const char *item) {
1437
1438 }
1439
1440 static void FileSelect(FileDialogData *fsb,
const char *item) {
1441 FileListSelect(fsb, item);
1442 FileListDetailSelect(fsb, item),
1443 FileIconViewSelect(fsb, item);
1444 }
1445
1446
1447
1448 #define FILE_ARRAY_SIZE 1024
1449
1450 void file_array_add(FileElm **files,
int *alloc,
int *count, FileElm elm) {
1451 int c = *count;
1452 int a = *alloc;
1453 if(c >= a) {
1454 a *=
2;
1455 FileElm *newarray = realloc(*files,
sizeof(FileElm) * a);
1456
1457 *files = newarray;
1458 *alloc = a;
1459 }
1460
1461 (*files)[c] = elm;
1462 c++;
1463 *count = c;
1464 }
1465
1466 static void filedialog_update_dir(FileDialogData *data,
char *path)
1467 {
1468 ViewUpdateFunc update_view =
NULL;
1469 switch(data->selectedview) {
1470 case 1: {
1471 cleanupLists(data);
1472 update_view = filedialog_update_lists;
1473 break;
1474 }
1475 case 2: {
1476 cleanupGrid(data);
1477 update_view = filedialog_update_grid;
1478 break;
1479 }
1480 }
1481
1482 char *openFile =
NULL;
1483
1484
1485 if(path) {
1486 struct stat s;
1487 int r = stat(path, &s);
1488 if((!r == !
S_ISDIR(s.st_mode)) || (r && errno ==
ENOENT && data->type ==
FILEDIALOG_SAVE)) {
1489
1490 if(data->selectedPath) {
1491 NEditFree(data->selectedPath);
1492 }
1493 data->selectedPath = NEditStrdup(path);
1494
1495 openFile = FileName(path);
1496 path = ParentPath(path);
1497
1498 PathBarSetPath(data->pathBar, path);
1499 }
1500
1501 FileElm *dirs = calloc(
sizeof(FileElm),
FILE_ARRAY_SIZE);
1502 FileElm *files = calloc(
sizeof(FileElm),
FILE_ARRAY_SIZE);
1503 int dirs_alloc =
FILE_ARRAY_SIZE;
1504 int files_alloc =
FILE_ARRAY_SIZE;
1505
1506 filedialog_cleanup_filedata(data);
1507
1508 int dircount =
0;
1509 int filecount =
0;
1510 size_t maxNameLen =
0;
1511 DIR *dir = opendir(path);
1512 if(!dir) {
1513 DialogF(
1514 DF_ERR,
1515 data->shell,
1516 1,
1517 "Error",
1518 "Directory %s cannot be opened: %s",
1519 "OK",
1520 path,
1521 strerror(errno));
1522 return;
1523 }
1524
1525
1526 char *oldPath = data->currentPath;
1527 data->currentPath = NEditStrdup(path);
1528 if(oldPath) {
1529 NEditFree(oldPath);
1530 }
1531 if(openFile) {
1532 NEditFree(path);
1533 }
1534 path = data->currentPath;
1535
1536 struct dirent *ent;
1537 while((ent = readdir(dir)) !=
NULL) {
1538 if(!strcmp(ent->d_name,
".") || !strcmp(ent->d_name,
"..")) {
1539 continue;
1540 }
1541
1542 char *entpath = ConcatPath(path, ent->d_name);
1543
1544 struct stat s;
1545 if(stat(entpath, &s)) {
1546 NEditFree(entpath);
1547 continue;
1548 }
1549
1550 FileElm new_entry;
1551 new_entry.path = entpath;
1552 new_entry.isDirectory =
S_ISDIR(s.st_mode);
1553 new_entry.size = (
uint64_t)s.st_size;
1554 new_entry.lastModified = s.st_mtime;
1555
1556 size_t nameLen = strlen(ent->d_name);
1557 if(nameLen > maxNameLen) {
1558 maxNameLen = nameLen;
1559 }
1560
1561 if(new_entry.isDirectory) {
1562 file_array_add(&dirs, &dirs_alloc, &dircount, new_entry);
1563 }
else {
1564 file_array_add(&files, &files_alloc, &filecount, new_entry);
1565 }
1566 }
1567 closedir(dir);
1568
1569 data->dirs = dirs;
1570 data->files = files;
1571 data->dircount = dircount;
1572 data->filecount = filecount;
1573 data->maxnamelen = maxNameLen;
1574
1575
1576 qsort(dirs, dircount,
sizeof(FileElm), filecmp);
1577 qsort(files, filecount,
sizeof(FileElm), filecmp);
1578 }
1579
1580 update_view(data, data->dirs, data->files,
1581 data->dircount, data->filecount, data->maxnamelen);
1582
1583 if(openFile) {
1584 FileSelect(data, openFile);
1585 data->status =
FILEDIALOG_OK;
1586 if(data->name) {
1587 XNETextSetString(data->name, openFile);
1588 XmProcessTraversal(data->name, XmTRAVERSE_CURRENT);
1589 }
else {
1590 select_view(data);
1591 }
1592 }
1593 }
1594
1595 static void filedialog_goup(Widget w, FileDialogData *data, XtPointer d)
1596 {
1597 char *newPath = ParentPath(data->currentPath);
1598 filedialog_update_dir(data, newPath);
1599 PathBarSetPath(data->pathBar, newPath);
1600 NEditFree(newPath);
1601 }
1602
1603 char* set_selected_path(FileDialogData *data, XmString item)
1604 {
1605 char *name =
NULL;
1606 XmStringGetLtoR(item, XmFONTLIST_DEFAULT_TAG, &name);
1607 if(!name) {
1608 return NULL;
1609 }
1610 char *path = ConcatPath(data->currentPath, name);
1611 XtFree(name);
1612
1613 if(data->selectedPath) {
1614 NEditFree(data->selectedPath);
1615 }
1616 data->selectedPath = path;
1617
1618 return path;
1619 }
1620
1621 void set_path_from_row(FileDialogData *data,
int row) {
1622 FileElm *elm =
NULL;
1623 XmLGridRow rowPtr = XmLGridGetRow(data->grid, XmCONTENT, row);
1624 XtVaGetValues(data->grid, XmNrowPtr, rowPtr, XmNrowUserData, &elm,
NULL);
1625 if(!elm) {
1626 fprintf(stderr,
"error: no row data\n");
1627 return;
1628 }
1629
1630 char *path = NEditStrdup(elm->path);
1631 filedialog_check_iofilters(data, path);
1632
1633 if(data->type ==
FILEDIALOG_SAVE) {
1634 XNETextSetString(data->name, FileName(path));
1635 NEditFree(path);
1636 }
else {
1637 if(data->selectedPath) {
1638 NEditFree(data->selectedPath);
1639 }
1640 data->selectedPath = path;
1641 data->selIsDir = False;
1642 }
1643 }
1644
1645 void grid_select(Widget w, FileDialogData *data, XmLGridCallbackStruct *cb) {
1646 set_path_from_row(data, cb->row);
1647 }
1648
1649 void grid_activate(Widget w, FileDialogData *data, XmLGridCallbackStruct *cb) {
1650 set_path_from_row(data, cb->row);
1651 filedialog_ok(w, data,
NULL);
1652 }
1653
1654 void grid_key_pressed(Widget w, FileDialogData *data, XmLGridCallbackStruct *cb) {
1655 char chars[
16];
1656 KeySym keysym;
1657 int nchars;
1658
1659 nchars = XLookupString(&cb->event->xkey, chars,
15, &keysym,
NULL);
1660
1661 if(nchars ==
0)
return;
1662
1663
1664
1665
1666
1667 int row =
0;
1668 int selectedRow = XmLGridGetSelectedRow(w);
1669
1670 int match = -
1;
1671
1672 for(
int i=
0;i<data->filecount;i++) {
1673 const char *name = FileName(data->files[i].path);
1674 if(!data->showHidden && name[
0] ==
'.')
continue;
1675
1676 size_t namelen = strlen(name);
1677
1678 size_t cmplen = namelen < nchars ? namelen : nchars;
1679 if(!memcmp(name, chars, cmplen)) {
1680 if(row <= selectedRow) {
1681 if(match == -
1) {
1682 match = row;
1683 }
1684 }
else {
1685 match = row;
1686 break;
1687 }
1688 }
1689
1690 row++;
1691 }
1692
1693 if(match > -
1) {
1694 XmLGridSelectRow(w, match, True);
1695 XmLGridFocusAndShowRow(w, match+
1);
1696 }
else {
1697 XBell(XtDisplay(w),
0);
1698 }
1699 }
1700
1701 void grid_header_clicked(Widget w, FileDialogData *data, XmLGridCallbackStruct *cb) {
1702 int new_cmp_field =
0;
1703 switch(cb->column) {
1704 case 0: {
1705 new_cmp_field =
0;
1706 break;
1707 }
1708 case 1: {
1709 new_cmp_field =
1;
1710 break;
1711 }
1712 case 2: {
1713 new_cmp_field =
2;
1714 break;
1715 }
1716 }
1717
1718 if(new_cmp_field == file_cmp_field) {
1719 file_cmp_order = -file_cmp_order;
1720 }
else {
1721 file_cmp_field = new_cmp_field;
1722 file_cmp_order =
1;
1723 }
1724
1725 int sort_type = file_cmp_order ==
1 ? XmSORT_ASCENDING : XmSORT_DESCENDING;
1726 XmLGridSetSort(data->grid, file_cmp_field, sort_type);
1727
1728 qsort(data->files, data->filecount,
sizeof(FileElm), filecmp);
1729
1730
1731 filedialog_update_dir(data,
NULL);
1732 }
1733
1734 void dirlist_activate(Widget w, FileDialogData *data, XmListCallbackStruct *cb)
1735 {
1736 char *path = set_selected_path(data, cb->item);
1737 if(path) {
1738 filedialog_update_dir(data, path);
1739 PathBarSetPath(data->pathBar, path);
1740 data->selIsDir =
TRUE;
1741 }
1742 }
1743
1744 void dirlist_select(Widget w, FileDialogData *data, XmListCallbackStruct *cb)
1745 {
1746 char *path = set_selected_path(data, cb->item);
1747 if(path) {
1748 data->selIsDir =
TRUE;
1749 }
1750 }
1751
1752 void filelist_activate(Widget w, FileDialogData *data, XmListCallbackStruct *cb)
1753 {
1754 char *path = set_selected_path(data, cb->item);
1755 if(path) {
1756 data->selIsDir = False;
1757 filedialog_ok(w, data,
NULL);
1758 }
1759 }
1760
1761 void filelist_select(Widget w, FileDialogData *data, XmListCallbackStruct *cb)
1762 {
1763 if(data->type ==
FILEDIALOG_SAVE) {
1764 char *name =
NULL;
1765 XmStringGetLtoR(cb->item, XmFONTLIST_DEFAULT_TAG, &name);
1766 XNETextSetString(data->name, name);
1767 char *path = name ? ConcatPath(data->currentPath, name) :
NULL;
1768 XtFree(name);
1769 filedialog_check_iofilters(data, path);
1770 XtFree(path);
1771 }
else {
1772 char *path = set_selected_path(data, cb->item);
1773 filedialog_check_iofilters(data, path);
1774 if(path) {
1775 data->selIsDir = False;
1776 }
1777 }
1778 }
1779
1780 static void filedialog_setshowhidden(
1781 Widget w,
1782 FileDialogData *data,
1783 XmToggleButtonCallbackStruct *tb)
1784 {
1785 data->showHidden = tb->set;
1786 filedialog_update_dir(data,
NULL);
1787 }
1788
1789 static void filedilalog_ok_end(FileDialogData *data)
1790 {
1791 struct stat s;
1792
1793 if(data->type ==
FILEDIALOG_OPEN) {
1794
1795 int fd = open(data->selectedPath,
O_RDONLY);
1796 if(fd == -
1) {
1797 FileOpenErrorDialog(data->shell, data->selectedPath);
1798 return;
1799 }
else {
1800 close(fd);
1801 }
1802
1803 }
else if(data->type ==
FILEDIALOG_SAVE && !stat(data->selectedPath, &s) &&
1804 (!data->file_path || strcmp(data->file_path, data->selectedPath)))
1805 {
1806 if(OverrideFileDialog(data->shell, FileName(data->selectedPath)) !=
1) {
1807 return;
1808 }
1809 }
1810
1811 data->status =
FILEDIALOG_OK;
1812 data->end = True;
1813 }
1814
1815 static void filedialog_ok(Widget w, FileDialogData *data, XtPointer d)
1816 {
1817 XmPushButtonCallbackStruct *cb = d;
1818 if(cb && w != data->name) {
1819 if(cb->event->type == KeyPress && cb->event->xkey.keycode ==
36) {
1820 return;
1821 }
1822 }
1823
1824 if(data->selectedPath) {
1825 if(!data->selIsDir) {
1826 filedilalog_ok_end(data);
1827 return;
1828 }
1829 }
1830
1831 if(data->type ==
FILEDIALOG_SAVE) {
1832 char *newName = XNETextGetString(data->name);
1833 if(newName) {
1834 if(strlen(newName) >
0) {
1835 data->selectedPath = newName[
0] ==
'/' ? NEditStrdup(newName) : ConcatPath(data->currentPath, newName);
1836 data->selIsDir =
0;
1837 filedilalog_ok_end(data);
1838 }
1839 XtFree(newName);
1840 }
1841 }
1842 }
1843
1844 #define DETECT_ENCODING "detect"
1845 static char *default_encodings[] = {
1846 DETECT_ENCODING,
1847 "UTF-8",
1848 "UTF-16",
1849 "UTF-16BE",
1850 "UTF-16LE",
1851 "UTF-32",
1852 "UTF-32BE",
1853 "UTF-32LE",
1854 "ISO8859-1",
1855 "ISO8859-2",
1856 "ISO8859-3",
1857 "ISO8859-4",
1858 "ISO8859-5",
1859 "ISO8859-6",
1860 "ISO8859-7",
1861 "ISO8859-8",
1862 "ISO8859-9",
1863 "ISO8859-10",
1864 "ISO8859-13",
1865 "ISO8859-14",
1866 "ISO8859-15",
1867 "ISO8859-16",
1868 NULL
1869 };
1870
1871 static void adjust_enc_settings(FileDialogData *data) {
1872
1873 if(data->type !=
FILEDIALOG_SAVE)
return;
1874
1875 int encPos;
1876 XtVaGetValues(data->encoding, XmNselectedPosition, &encPos,
NULL);
1877
1878
1879
1880
1881
1882 if(encPos >
6) {
1883
1884 XtSetSensitive(data->bom, False);
1885 if(GetAutoEnableXattr()) {
1886 XtVaSetValues(data->xattr, XmNset,
1,
NULL);
1887 }
1888 }
else {
1889 XtSetSensitive(data->bom, True);
1890 if(encPos >
0) {
1891
1892 XtVaSetValues(data->bom, XmNset,
1,
NULL);
1893 }
1894 }
1895 }
1896
1897 static void filedialog_select_encoding(
1898 Widget w,
1899 FileDialogData *data,
1900 XmComboBoxCallbackStruct *cb)
1901 {
1902 if(cb->reason == XmCR_SELECT) {
1903 adjust_enc_settings(data);
1904 }
1905 }
1906
1907 static int str_has_suffix(
const char *str,
const char *suffix) {
1908 size_t str_len = str ? strlen(str) :
0;
1909 size_t suffix_len = suffix ? strlen(suffix) :
0;
1910 if(str_len >= suffix_len) {
1911 const char *str_end = str + str_len - suffix_len;
1912 int result = memcmp(str_end, suffix, suffix_len) ==
0;
1913 return result;
1914 }
1915 return 0;
1916 }
1917
1918 static void filedialog_select_iofilter(
1919 Widget w,
1920 FileDialogData *data,
1921 XmComboBoxCallbackStruct *cb)
1922 {
1923 if(cb->reason == XmCR_SELECT) {
1924 if(data->type ==
FILEDIALOG_SAVE) {
1925
1926 if(data->selected_filter) {
1927
1928 char *name = XNETextGetString(data->name);
1929 size_t name_len = strlen(name);
1930 if(str_has_suffix(name, data->selected_filter->ext)) {
1931 name[name_len - strlen(data->selected_filter->ext)] =
0;
1932 XNETextSetString(data->name, name);
1933 }
1934 XtFree(name);
1935 }
1936 }
1937
1938
1939 int selectedFilterIndex;
1940 XtVaGetValues(data->iofilter, XmNselectedPosition, &selectedFilterIndex,
NULL);
1941
1942 if(selectedFilterIndex ==
0) {
1943 data->selected_filter =
NULL;
1944 }
else {
1945
1946 data->selected_filter = data->filters[selectedFilterIndex-
1];
1947
1948
1949 if(data->name && data->selected_filter->ext) {
1950 char *name = XNETextGetString(data->name);
1951 if(!str_has_suffix(name, data->selected_filter->ext)) {
1952 size_t name_len = strlen(name);
1953 size_t ext_len = strlen(data->selected_filter->ext);
1954 size_t newname_len = name_len + ext_len;
1955 char *newname = NEditMalloc(newname_len +
1);
1956 memcpy(newname, name, name_len);
1957 memcpy(newname+name_len, data->selected_filter->ext, ext_len);
1958 newname[newname_len] =
'\0';
1959 XNETextSetString(data->name, newname);
1960 NEditFree(newname);
1961 }
1962 XtFree(name);
1963 }
1964 }
1965 }
1966 }
1967
1968 static void filedialog_filter(Widget w, FileDialogData *data, XtPointer c)
1969 {
1970 filedialog_update_dir(data,
NULL);
1971 }
1972
1973 static void unselect_view(FileDialogData *data)
1974 {
1975 switch(data->selectedview) {
1976 case 1: {
1977 XtUnmanageChild(data->listform);
1978 XtUnmanageChild(data->filelistcontainer);
1979 cleanupLists(data);
1980 break;
1981 }
1982 case 2: {
1983 XtUnmanageChild(data->listform);
1984 XtUnmanageChild(data->gridcontainer);
1985 cleanupGrid(data);
1986
1987
1988 file_cmp_field =
0;
1989 file_cmp_order =
1;
1990 qsort(data->files, data->filecount,
sizeof(FileElm), filecmp);
1991
1992 break;
1993 }
1994 }
1995 }
1996
1997 static void select_listview(Widget w, FileDialogData *data, XtPointer u)
1998 {
1999 unselect_view(data);
2000 data->selectedview =
1;
2001 XtManageChild(data->listform);
2002 XtManageChild(data->filelistcontainer);
2003 filedialog_update_dir(data,
NULL);
2004 data->pathBar->focus_widget = data->filelist;
2005 XmProcessTraversal(data->filelist, XmTRAVERSE_CURRENT);
2006 }
2007
2008 static void select_detailview(Widget w, FileDialogData *data, XtPointer u)
2009 {
2010
2011
2012 unselect_view(data);
2013 data->selectedview =
2;
2014 XtManageChild(data->listform);
2015 XtManageChild(data->gridcontainer);
2016 filedialog_update_dir(data,
NULL);
2017 data->pathBar->focus_widget = data->grid;
2018 XmProcessTraversal(data->grid, XmTRAVERSE_CURRENT);
2019 }
2020
2021 static void select_view(FileDialogData *data)
2022 {
2023 Widget w;
2024 switch(data->selectedview) {
2025 default:
return;
2026 case 0: w = data->grid;
break;
2027 case 1: w = data->filelist;
break;
2028 }
2029 XmProcessTraversal(w, XmTRAVERSE_CURRENT);
2030 }
2031
2032 static void new_folder(Widget w, FileDialogData *data, XtPointer u)
2033 {
2034 char fileName[
DF_MAX_PROMPT_LENGTH];
2035 fileName[
0] =
0;
2036
2037 int response = DialogF(
2038 DF_PROMPT,
2039 data->shell,
2040 2,
2041 "Create new directory",
"Directory name:",
2042 fileName,
2043 "OK",
2044 "Cancel");
2045
2046 if(response ==
2 || strlen(fileName) ==
0) {
2047 return;
2048 }
2049
2050 char *newFolder = ConcatPath(data->currentPath ? data->currentPath :
"", fileName);
2051 if(mkdir(newFolder,
S_IRWXU |
S_IRGRP |
S_IXGRP |
S_IROTH |
S_IXOTH)) {
2052 DialogF(
2053 DF_ERR,
2054 data->shell,
2055 1,
2056 "Error creating Directory",
2057 "Can''t create %s:\n%s",
"OK",
2058 newFolder,
2059 strerror(errno));
2060 }
else {
2061 char *p = strdup(data->currentPath);
2062 filedialog_update_dir(data, p);
2063 free(p);
2064 }
2065 free(newFolder);
2066 }
2067
2068 static unsigned int keycodeL;
2069
2070 static void shortcutEH(Widget widget, XtPointer data, XEvent *event, Boolean *dispatch)
2071 {
2072 FileDialogData *fsb = data;
2073 if(event->xkey.keycode == keycodeL) {
2074 PathBarActivateTextfield(fsb->pathBar);
2075 *dispatch = False;
2076 }
2077 }
2078
2079 static void createFilterWidgets(FileDialogData *data,
const char *current_filter, Widget parent, Arg *args,
int n) {
2080 size_t nfilters;
2081 IOFilter **filter = GetFilterList(&nfilters);
2082 data->filters = filter;
2083 data->nfilters = nfilters;
2084
2085 XmStringTable filterStrTable = NEditCalloc(nfilters+
1,
sizeof(XmString));
2086 filterStrTable[
0] = XmStringCreateSimple(
"-");
2087 for(
int i=
0;i<nfilters;i++) {
2088 filterStrTable[i+
1] = XmStringCreateLocalized(filter[i]->name);
2089 }
2090
2091 XtSetArg(args[n], XmNcolumns,
11); n++;
2092 XtSetArg(args[n], XmNitemCount, nfilters+
1); n++;
2093 XtSetArg(args[n], XmNitems, filterStrTable); n++;
2094 data->iofilter = XmCreateDropDownList(parent,
"filtercombobox", args, n);
2095 XtManageChild(data->iofilter);
2096 for(
int i=
0;i<nfilters+
1;i++) {
2097 XmStringFree(filterStrTable[i]);
2098 }
2099 NEditFree(filterStrTable);
2100
2101 XtAddCallback(
2102 data->iofilter,
2103 XmNselectionCallback,
2104 (XtCallbackProc)filedialog_select_iofilter,
2105 data);
2106
2107 if(current_filter) {
2108 XmString xCurrentFilter = XmStringCreateLocalized((
char*)current_filter);
2109 XmComboBoxSelectItem(data->iofilter, xCurrentFilter);
2110 XmStringFree(xCurrentFilter);
2111
2112 XmComboBoxCallbackStruct cb;
2113 cb.reason = XmCR_SELECT;
2114 filedialog_select_iofilter(data->iofilter, data, &cb);
2115 }
2116 }
2117
2118 int FileDialog(Widget parent,
char *promptString, FileSelection *file,
int type,
const char *defaultName)
2119 {
2120 Arg args[
32];
2121 int n =
0;
2122 XmString str;
2123
2124 int currentEncItem =
0;
2125
2126 if(LastView == -
1) {
2127 LastView = GetFsbView();
2128 if(LastView <
0 || LastView >
2) {
2129 LastView =
1;
2130 }
2131 }
2132 #ifndef FSB_ENABLE_DETAIL
2133 if(LastView ==
2) {
2134 LastView =
1;
2135 }
2136 #endif
2137 Boolean showHiddenValue = GetFsbShowHidden();
2138
2139 FileDialogData data;
2140 memset(&data,
0,
sizeof(FileDialogData));
2141 data.type = type;
2142 data.file_path = file->path;
2143
2144 file->addwrap =
FALSE;
2145 file->setxattr =
FALSE;
2146
2147 Widget dialog = CreateDialogShell(parent, promptString, args,
0);
2148 AddMotifCloseCallback(dialog, (XtCallbackProc)filedialog_cancel, &data);
2149 data.shell = dialog;
2150
2151
2152 XtAddEventHandler(dialog, KeyPressMask , False,
2153 (XtEventHandler)shortcutEH, &data);
2154
2155 n =
0;
2156 XtSetArg(args[n], XmNautoUnmanage, False); n++;
2157 Widget form = XmCreateForm(dialog,
"form", args, n);
2158
2159
2160
2161 n =
0;
2162 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
2163 XtSetArg(args[n], XmNtopOffset,
WINDOW_SPACING); n++;
2164 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2165 XtSetArg(args[n], XmNleftOffset,
WINDOW_SPACING); n++;
2166 XtSetArg(args[n], XmNresizable, True); n++;
2167 XtSetArg(args[n], XmNarrowDirection, XmARROW_UP); n++;
2168 Widget goUp = XmCreateArrowButton(form,
"button", args, n);
2169
2170 XtAddCallback(goUp, XmNactivateCallback,
2171 (XtCallbackProc)filedialog_goup, &data);
2172
2173
2174 n =
0;
2175 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
2176 XtSetArg(args[n], XmNtopOffset,
WINDOW_SPACING); n++;
2177 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
2178 XtSetArg(args[n], XmNrightOffset,
WINDOW_SPACING); n++;
2179 XtSetArg(args[n], XmNshadowThickness,
0); n++;
2180 Widget viewframe = XmCreateForm(form,
"vframe", args, n);
2181 XtManageChild(viewframe);
2182
2183 XmString v1 = XmStringCreateLocalized(
"List");
2184 XmString v2 = XmStringCreateLocalized(
"Detail");
2185
2186 Widget menu = XmCreatePulldownMenu(viewframe,
"menu",
NULL,
0);
2187
2188 XtSetArg(args[
0], XmNlabelString, v1);
2189 XtSetArg(args[
1], XmNpositionIndex, LastView ==
1 ?
0 :
1);
2190 Widget mitem1 = XmCreatePushButton(menu,
"menuitem", args,
2);
2191 XtSetArg(args[
0], XmNlabelString, v2);
2192 XtSetArg(args[
1], XmNpositionIndex, LastView ==
2 ?
0 :
2);
2193 Widget mitem2 = XmCreatePushButton(menu,
"menuitem", args,
2);
2194 XtManageChild(mitem1);
2195 #ifdef FSB_ENABLE_DETAIL
2196 XtManageChild(mitem2);
2197 #endif
2198 XmStringFree(v1);
2199 XmStringFree(v2);;
2200 XtAddCallback(
2201 mitem1,
2202 XmNactivateCallback,
2203 (XtCallbackProc)select_listview,
2204 &data);
2205 XtAddCallback(
2206 mitem2,
2207 XmNactivateCallback,
2208 (XtCallbackProc)select_detailview,
2209 &data);
2210
2211 n =
0;
2212 XtSetArg(args[n], XmNsubMenuId, menu); n++;
2213 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
2214 XtSetArg(args[n], XmNmarginHeight,
0); n++;
2215 XtSetArg(args[n], XmNmarginWidth,
0); n++;
2216 Widget view = XmCreateOptionMenu(viewframe,
"option_menu", args, n);
2217 XtManageChild(view);
2218
2219 n =
0;
2220 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2221 XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
2222 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
2223 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
2224 XtSetArg(args[n], XmNrightWidget, view); n++;
2225 XtSetArg(args[n], XmNmarginHeight,
0); n++;
2226 XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
2227 Widget newFolder = XmCreatePushButton(viewframe,
"newFolder", args, n);
2228 XtManageChild(newFolder);
2229 XtAddCallback(
2230 newFolder,
2231 XmNactivateCallback,
2232 (XtCallbackProc)new_folder,
2233 &data);
2234
2235 Dimension xh;
2236 Pixel buttonFg;
2237 Pixel buttonBg;
2238 XtVaGetValues(newFolder, XmNheight, &xh, XmNforeground, &buttonFg, XmNbackground, &buttonBg,
NULL);
2239
2240
2241 memset(&bgColor,
0,
sizeof(XColor));
2242 bgColor.pixel = buttonBg;
2243 XQueryColor(XtDisplay(newFolder), newFolder->core.colormap, &bgColor);
2244
2245
2246 if(!pixmaps_initialized) {
2247 initPixmaps(XtDisplay(parent), XtWindow(parent), newFolder->core.screen, newFolder->core.depth);
2248 }
2249
2250 if(pixmaps_error) {
2251 XtVaSetValues(newFolder, XmNlabelType, XmSTRING,
NULL);
2252 }
else if(xh >
32+
BUTTON_EXTRA_SPACE) {
2253 XtVaSetValues(newFolder, XmNlabelPixmap, newFolderIcon32,
NULL);
2254 }
else if(xh >
24+
BUTTON_EXTRA_SPACE) {
2255 XtVaSetValues(newFolder, XmNlabelPixmap, newFolderIcon24,
NULL);
2256 }
else {
2257 XtVaSetValues(newFolder, XmNlabelPixmap, newFolderIcon16,
NULL);
2258 }
2259
2260
2261 n =
0;
2262 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
2263 XtSetArg(args[n], XmNtopOffset,
WINDOW_SPACING); n++;
2264 XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
2265 XtSetArg(args[n], XmNleftWidget, goUp); n++;
2266 XtSetArg(args[n], XmNleftOffset,
WINDOW_SPACING); n++;
2267 XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
2268 XtSetArg(args[n], XmNrightWidget, viewframe); n++;
2269 XtSetArg(args[n], XmNrightOffset,
WIDGET_SPACING); n++;
2270 XtSetArg(args[n], XmNshadowType, XmSHADOW_IN); n++;
2271 Widget pathBarFrame = XmCreateFrame(form,
"pathbar_frame", args, n);
2272 XtManageChild(pathBarFrame);
2273 data.pathBar = CreatePathBar(pathBarFrame, args,
0);
2274 data.pathBar->updateDir = (updatedir_callback)filedialog_update_dir;
2275 data.pathBar->updateDirData = &data;
2276 XtManageChild(data.pathBar->widget);
2277
2278 n =
0;
2279 str = XmStringCreateLocalized(
"Filter");
2280 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2281 XtSetArg(args[n], XmNleftOffset,
WINDOW_SPACING); n++;
2282 XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
2283 XtSetArg(args[n], XmNtopWidget, pathBarFrame); n++;
2284 XtSetArg(args[n], XmNtopOffset,
WIDGET_SPACING); n++;
2285 XtSetArg(args[n], XmNlabelString, str); n++;
2286 Widget filterLabel = XmCreateLabel(form,
"label", args, n);
2287 XtManageChild(filterLabel);
2288 XmStringFree(str);
2289
2290 n =
0;
2291 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2292 XtSetArg(args[n], XmNleftOffset,
WINDOW_SPACING); n++;
2293 XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
2294 XtSetArg(args[n], XmNtopWidget, filterLabel); n++;
2295 XtSetArg(args[n], XmNtopOffset,
WIDGET_SPACING); n++;
2296 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
2297 XtSetArg(args[n], XmNrightOffset,
WINDOW_SPACING); n++;
2298 Widget filterform = XmCreateForm(form,
"filterform", args, n);
2299 XtManageChild(filterform);
2300
2301 n =
0;
2302 str = XmStringCreateSimple(
"Show hidden files");
2303 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
2304 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
2305 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
2306 XtSetArg(args[n], XmNlabelString, str); n++;
2307 XtSetArg(args[n], XmNset, showHiddenValue); n++;
2308 Widget showHidden = XmCreateToggleButton(filterform,
"showHidden", args, n);
2309 XtManageChild(showHidden);
2310 XmStringFree(str);
2311 XtAddCallback(showHidden, XmNvalueChangedCallback,
2312 (XtCallbackProc)filedialog_setshowhidden, &data);
2313 data.showHidden = showHiddenValue;
2314
2315 n =
0;
2316 str = XmStringCreateLocalized(
"Filter");
2317 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
2318 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
2319 XtSetArg(args[n], XmNlabelString, str); n++;
2320 XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
2321 XtSetArg(args[n], XmNrightWidget, showHidden); n++;
2322 Widget filterButton = XmCreatePushButton(filterform,
"filedialog_filter", args, n);
2323 XtManageChild(filterButton);
2324 XmStringFree(str);
2325 XtAddCallback(filterButton, XmNactivateCallback,
2326 (XtCallbackProc)filedialog_filter, &data);
2327
2328 n =
0;
2329 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
2330 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
2331 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2332 XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
2333 XtSetArg(args[n], XmNrightWidget, filterButton); n++;
2334 XtSetArg(args[n], XmNrightOffset,
WIDGET_SPACING); n++;
2335 data.filter = XNECreateText(filterform,
"filedialog_filter_textfield", args, n);
2336 XtManageChild(data.filter);
2337 XtAddCallback(data.filter, XmNactivateCallback,
2338 (XtCallbackProc)filedialog_filter, &data);
2339 if(LastFilter) {
2340 XNETextSetString(data.filter, LastFilter);
2341 XtFree(LastFilter);
2342 LastFilter =
NULL;
2343 }
else {
2344 XNETextSetString(data.filter,
"*");
2345 }
2346
2347
2348 n =
0;
2349 str = XmStringCreateLocalized(type ==
FILEDIALOG_OPEN ?
"Open" :
"Save");
2350 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
2351 XtSetArg(args[n], XmNbottomOffset,
WINDOW_SPACING); n++;
2352 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2353 XtSetArg(args[n], XmNleftOffset,
WINDOW_SPACING); n++;
2354 XtSetArg(args[n], XmNtopOffset,
WIDGET_SPACING *
2); n++;
2355 XtSetArg(args[n], XmNlabelString, str); n++;
2356 data.okBtn = XmCreatePushButton(form,
"filedialog_open", args, n);
2357 XtManageChild(data.okBtn);
2358 XmStringFree(str);
2359 XtAddCallback(data.okBtn, XmNactivateCallback,
2360 (XtCallbackProc)filedialog_ok, &data);
2361
2362 n =
0;
2363 str = XmStringCreateLocalized(
"Cancel");
2364 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
2365 XtSetArg(args[n], XmNbottomOffset,
WINDOW_SPACING); n++;
2366 XtSetArg(args[n], XmNlabelString, str); n++;
2367 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
2368 XtSetArg(args[n], XmNrightOffset,
WINDOW_SPACING); n++;
2369 Widget cancelBtn = XmCreatePushButton(form,
"filedialog_cancel", args, n);
2370 XtManageChild(cancelBtn);
2371 XmStringFree(str);
2372 XtAddCallback(cancelBtn, XmNactivateCallback,
2373 (XtCallbackProc)filedialog_cancel, &data);
2374
2375 XtVaSetValues(form, XmNdefaultButton, data.okBtn, XmNcancelButton, cancelBtn,
NULL);
2376
2377 n =
0;
2378 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
2379 XtSetArg(args[n], XmNbottomWidget, data.okBtn); n++;
2380 XtSetArg(args[n], XmNbottomOffset,
WIDGET_SPACING); n++;
2381 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2382 XtSetArg(args[n], XmNleftOffset,
1); n++;
2383 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
2384 XtSetArg(args[n], XmNrightOffset,
1); n++;
2385 Widget separator = XmCreateSeparator(form,
"ofd_separator", args, n);
2386 XtManageChild(separator);
2387
2388 Widget bottomWidget = separator;
2389
2390 if(type ==
FILEDIALOG_SAVE) {
2391 if(file->extraoptions) {
2392 n =
0;
2393 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
2394 XtSetArg(args[n], XmNbottomWidget, separator); n++;
2395 XtSetArg(args[n], XmNbottomOffset,
WIDGET_SPACING); n++;
2396 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
2397 XtSetArg(args[n], XmNrightOffset,
WINDOW_SPACING); n++;
2398 createFilterWidgets(&data, file->filter, form, args, n);
2399
2400 n =
0;
2401 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
2402 XtSetArg(args[n], XmNbottomWidget, separator); n++;
2403 XtSetArg(args[n], XmNbottomOffset,
WIDGET_SPACING); n++;
2404 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2405 XtSetArg(args[n], XmNleftOffset,
WINDOW_SPACING); n++;
2406 XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
2407 XtSetArg(args[n], XmNrightWidget, data.iofilter); n++;
2408 XtSetArg(args[n], XmNrightOffset,
WIDGET_SPACING); n++;
2409
2410
2411 data.name = XNECreateText(form,
"textfield", args, n);
2412 XtManageChild(data.name);
2413 XtAddCallback(data.name, XmNactivateCallback,
2414 (XtCallbackProc)filedialog_ok, &data);
2415 if(defaultName) {
2416 XNETextSetString(data.name, (
char*)defaultName);
2417 }
2418
2419 n =
0;
2420 str = XmStringCreateSimple(
"Filter");
2421 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
2422 XtSetArg(args[n], XmNbottomWidget, data.name); n++;
2423 XtSetArg(args[n], XmNbottomOffset,
WIDGET_SPACING); n++;
2424 XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
2425 XtSetArg(args[n], XmNleftWidget, data.name); n++;
2426 XtSetArg(args[n], XmNleftOffset,
WIDGET_SPACING); n++;
2427 XtSetArg(args[n], XmNlabelString, str); n++;
2428 Widget filterLabel = XmCreateLabel(form,
"label", args, n);
2429 XtManageChild(filterLabel);
2430 XmStringFree(str);
2431
2432 n =
0;
2433 str = XmStringCreateSimple(
"New File Name");
2434 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
2435 XtSetArg(args[n], XmNbottomWidget, data.name); n++;
2436 XtSetArg(args[n], XmNbottomOffset,
WIDGET_SPACING); n++;
2437 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2438 XtSetArg(args[n], XmNleftOffset,
WINDOW_SPACING); n++;
2439 XtSetArg(args[n], XmNlabelString, str); n++;
2440 Widget nameLabel = XmCreateLabel(form,
"label", args, n);
2441 XtManageChild(nameLabel);
2442 XmStringFree(str);
2443
2444 n =
0;
2445 str = XmStringCreateSimple(
"Add line breaks where wrapped");
2446 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
2447 XtSetArg(args[n], XmNbottomWidget, nameLabel); n++;
2448 XtSetArg(args[n], XmNbottomOffset,
WIDGET_SPACING); n++;
2449 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2450 XtSetArg(args[n], XmNleftOffset,
WINDOW_SPACING); n++;
2451 XtSetArg(args[n], XmNmnemonic,
'A'); n++;
2452 XtSetArg(args[n], XmNlabelString, str); n++;
2453 data.wrap = XmCreateToggleButton(form,
"addWrap", args, n);
2454 XtManageChild(data.wrap);
2455 XmStringFree(str);
2456
2457 Widget formatBtns = CreateFormatButtons(
2458 form,
2459 data.wrap,
2460 file->format,
2461 &data.unixFormat,
2462 &data.dosFormat,
2463 &data.macFormat);
2464
2465 bottomWidget = formatBtns;
2466 }
else {
2467 n =
0;
2468 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
2469 XtSetArg(args[n], XmNbottomWidget, separator); n++;
2470 XtSetArg(args[n], XmNbottomOffset,
WIDGET_SPACING); n++;
2471 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2472 XtSetArg(args[n], XmNleftOffset,
WINDOW_SPACING); n++;
2473 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
2474 XtSetArg(args[n], XmNrightOffset,
WINDOW_SPACING); n++;
2475
2476
2477 data.name = XNECreateText(form,
"textfield", args, n);
2478 XtManageChild(data.name);
2479 XtAddCallback(data.name, XmNactivateCallback,
2480 (XtCallbackProc)filedialog_ok, &data);
2481 if(defaultName) {
2482 XNETextSetString(data.name, (
char*)defaultName);
2483 }
2484
2485 n =
0;
2486 str = XmStringCreateSimple(
"New File Name");
2487 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
2488 XtSetArg(args[n], XmNbottomWidget, data.name); n++;
2489 XtSetArg(args[n], XmNbottomOffset,
WIDGET_SPACING); n++;
2490 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2491 XtSetArg(args[n], XmNleftOffset,
WINDOW_SPACING); n++;
2492 XtSetArg(args[n], XmNlabelString, str); n++;
2493 Widget nameLabel = XmCreateLabel(form,
"label", args, n);
2494 XtManageChild(nameLabel);
2495 XmStringFree(str);
2496
2497 bottomWidget = nameLabel;
2498 }
2499 }
2500
2501 n =
0;
2502 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
2503 XtSetArg(args[n], XmNbottomWidget, bottomWidget); n++;
2504 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2505 XtSetArg(args[n], XmNleftOffset,
WINDOW_SPACING); n++;
2506 XtSetArg(args[n], XmNbottomOffset,
WIDGET_SPACING); n++;
2507 XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
2508 Widget enc = XmCreateRowColumn(form,
"enc", args, n);
2509 XtManageChild(enc);
2510
2511 if(file->extraoptions) {
2512 n =
0;
2513 str = XmStringCreateSimple(
"Encoding:");
2514 XtSetArg(args[n], XmNlabelString, str); n++;
2515 Widget encLabel = XmCreateLabel(enc,
"label", args, n);
2516 XtManageChild(encLabel);
2517 XmStringFree(str);
2518
2519 n =
0;
2520 int arraylen =
22;
2521
2522
2523
2524 const char *encStr;
2525 XmStringTable encodings = NEditCalloc(arraylen,
sizeof(XmString));
2526
2527 int skip = type ==
FILEDIALOG_OPEN ?
0 :
1;
2528 char *defEncoding = type ==
FILEDIALOG_OPEN ?
NULL : file->encoding;
2529 int hasDef =
0;
2530 int i;
2531 for(i=skip;(encStr=default_encodings[i]);i++) {
2532 if(i >= arraylen) {
2533 arraylen *=
2;
2534 encodings = NEditRealloc(encodings, arraylen *
sizeof(XmString));
2535 }
2536 encodings[i] = XmStringCreateSimple((
char*)encStr);
2537 if(defEncoding) {
2538 if(!strcasecmp(defEncoding, encStr)) {
2539 hasDef =
1;
2540 defEncoding =
NULL;
2541 }
2542 }
2543 }
2544 if(skip ==
1 && !hasDef && file->encoding) {
2545
2546
2547
2548
2549 encodings[
0] = XmStringCreateSimple(file->encoding);
2550 currentEncItem =
1;
2551 skip =
0;
2552 }
2553 XtSetArg(args[n], XmNcolumns,
11); n++;
2554 XtSetArg(args[n], XmNitemCount, i-skip); n++;
2555 XtSetArg(args[n], XmNitems, encodings+skip); n++;
2556 data.encoding = XmCreateDropDownList(enc,
"combobox", args, n);
2557 XtManageChild(data.encoding);
2558 for(
int j=
0;j<i;j++) {
2559 XmStringFree(encodings[j]);
2560 }
2561 NEditFree(encodings);
2562
2563 if(file->encoding) {
2564 char *encStr = NEditStrdup(file->encoding);
2565 size_t encLen = strlen(encStr);
2566 for(
int i=
0;i<encLen;i++) {
2567 encStr[i] = toupper(encStr[i]);
2568 }
2569 str = XmStringCreateSimple(encStr);
2570 XmComboBoxSelectItem(data.encoding, str);
2571 XmStringFree(str);
2572 NEditFree(encStr);
2573 }
2574
2575
2576 if(type ==
FILEDIALOG_SAVE) {
2577
2578 XtAddCallback(
2579 data.encoding,
2580 XmNselectionCallback,
2581 (XtCallbackProc)filedialog_select_encoding,
2582 &data);
2583
2584 n =
0;
2585 str = XmStringCreateSimple(
"Write BOM");
2586 XtSetArg(args[n], XmNlabelString, str); n++;
2587 XtSetArg(args[n], XmNset, file->writebom); n++;
2588 data.bom = XmCreateToggleButton(enc,
"togglebutton", args, n);
2589 XtManageChild(data.bom);
2590 XmStringFree(str);
2591
2592 n =
0;
2593 str = XmStringCreateSimple(
"Store encoding in extended attribute");
2594 XtSetArg(args[n], XmNlabelString, str); n++;
2595 data.xattr = XmCreateToggleButton(enc,
"togglebutton", args, n);
2596 XtManageChild(data.xattr);
2597 XmStringFree(str);
2598 }
else {
2599
2600 n =
0;
2601 XmString str = XmStringCreateSimple(
"Filter");
2602 XtSetArg(args[n], XmNlabelString, str); n++;
2603 Widget filterLabel = XmCreateLabel(enc,
"filter_label", args, n);
2604 XtManageChild(filterLabel);
2605 XmStringFree(str);
2606
2607 createFilterWidgets(&data, file->filter, enc, args,
0);
2608 }
2609
2610 }
2611
2612
2613 data.selectedview = LastView;
2614
2615
2616 n =
0;
2617 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2618 XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
2619 XtSetArg(args[n], XmNtopWidget, filterform); n++;
2620 XtSetArg(args[n], XmNtopOffset,
WIDGET_SPACING); n++;
2621 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
2622 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
2623 XtSetArg(args[n], XmNbottomWidget, enc); n++;
2624 XtSetArg(args[n], XmNleftOffset,
WINDOW_SPACING); n++;
2625 XtSetArg(args[n], XmNrightOffset,
WINDOW_SPACING); n++;
2626 XtSetArg(args[n], XmNbottomOffset,
WIDGET_SPACING); n++;
2627 XtSetArg(args[n], XmNwidth,
580); n++;
2628 XtSetArg(args[n], XmNheight,
400); n++;
2629 data.listform = XmCreateForm(form,
"fds_listform", args, n);
2630
2631
2632 n =
0;
2633 str = XmStringCreateLocalized(
"Directories");
2634 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
2635 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2636 XtSetArg(args[n], XmNlabelString, str); n++;
2637 Widget lsDirLabel = XmCreateLabel(data.listform,
"label", args, n);
2638 XtManageChild(lsDirLabel);
2639 XmStringFree(str);
2640
2641 n =
0;
2642 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2643 XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
2644 XtSetArg(args[n], XmNtopWidget, lsDirLabel); n++;
2645 XtSetArg(args[n], XmNtopOffset,
WIDGET_SPACING); n++;
2646 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
2647 XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
2648 XtSetArg(args[n], XmNrightPosition,
35); n++;
2649 data.dirlist = XmCreateScrolledList(data.listform,
"dirlist", args, n);
2650 Dimension w, h;
2651 XtMakeResizeRequest(data.dirlist,
150,
200, &w, &h);
2652 XtManageChild(data.dirlist);
2653 XtAddCallback(
2654 data.dirlist,
2655 XmNdefaultActionCallback,
2656 (XtCallbackProc)dirlist_activate,
2657 &data);
2658 XtAddCallback(
2659 data.dirlist,
2660 XmNbrowseSelectionCallback,
2661 (XtCallbackProc)dirlist_select,
2662 &data);
2663
2664 n =
0;
2665 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
2666 XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
2667 XtSetArg(args[n], XmNtopWidget, lsDirLabel); n++;
2668 XtSetArg(args[n], XmNtopOffset,
WIDGET_SPACING); n++;
2669 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
2670 XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
2671 XtSetArg(args[n], XmNleftWidget, data.dirlist); n++;
2672 XtSetArg(args[n], XmNleftOffset,
WIDGET_SPACING); n++;
2673 XtSetArg(args[n], XmNshadowThickness,
0); n++;
2674 data.filelistcontainer = XmCreateFrame(data.listform,
"filelistframe", args, n);
2675
2676
2677 data.filelist = XmCreateScrolledList(data.filelistcontainer,
"filelist",
NULL,
0);
2678 XtManageChild(data.filelist);
2679 XtAddCallback(
2680 data.filelist,
2681 XmNdefaultActionCallback,
2682 (XtCallbackProc)filelist_activate,
2683 &data);
2684 XtAddCallback(
2685 data.filelist,
2686 XmNbrowseSelectionCallback,
2687 (XtCallbackProc)filelist_select,
2688 &data);
2689
2690
2691
2692
2693
2694 n =
0;
2695 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
2696 XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
2697 XtSetArg(args[n], XmNtopWidget, lsDirLabel); n++;
2698 XtSetArg(args[n], XmNtopOffset,
WIDGET_SPACING); n++;
2699 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
2700 XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
2701 XtSetArg(args[n], XmNleftWidget, data.dirlist); n++;
2702 XtSetArg(args[n], XmNleftOffset,
WIDGET_SPACING); n++;
2703 XtSetArg(args[n], XmNshadowThickness,
0); n++;
2704 data.gridcontainer = XmCreateFrame(data.listform,
"gridcontainer", args, n);
2705
2706
2707 n =
0;
2708 XtSetArg(args[n], XmNcolumns,
3); n++;
2709 XtSetArg(args[n], XmNheadingColumns,
0); n++;
2710 XtSetArg(args[n], XmNheadingRows,
1); n++;
2711 XtSetArg(args[n], XmNallowColumnResize,
1); n++;
2712 XtSetArg(args[n], XmNsimpleHeadings,
"Name|Size|Last Modified"); n++;
2713 XtSetArg(args[n], XmNhorizontalSizePolicy, XmCONSTANT); n++;
2714
2715 data.grid = XmLCreateGrid(data.gridcontainer,
"grid", args, n);
2716 XmLGridSetIgnoreModifyVerify(data.grid, True);
2717 int sort_type = file_cmp_order ==
1 ? XmSORT_ASCENDING : XmSORT_DESCENDING;
2718 XmLGridSetSort(data.grid, file_cmp_field, sort_type);
2719 XtManageChild(data.grid);
2720
2721
2722 const char *cellBg =
"white";
2723 XrmValue value;
2724 char *resourceType =
NULL;
2725
2726
2727 if(XrmGetResource(XtDatabase(XtDisplay(data.grid)),
"XmList.background",
NULL, &resourceType, &value)) {
2728 if(!strcmp(resourceType,
"String")) {
2729 cellBg = value.addr;
2730 }
2731 }
2732
2733 XtVaSetValues(
2734 data.grid,
2735 XmNcellDefaults, True,
2736 XtVaTypedArg, XmNblankBackground, XmRString, cellBg, strlen(cellBg),
2737 XtVaTypedArg, XmNcellBackground, XmRString, cellBg, strlen(cellBg),
2738 NULL);
2739
2740
2741 XtAddCallback(data.grid, XmNselectCallback, (XtCallbackProc)grid_select, &data);
2742 XtAddCallback(data.grid, XmNactivateCallback, (XtCallbackProc)grid_activate, &data);
2743 XtAddCallback(data.grid, XmNheaderClickCallback, (XtCallbackProc)grid_header_clicked, &data);
2744 XtAddCallback(data.grid, XmNgridKeyPressedCallback, (XtCallbackProc)grid_key_pressed, &data);
2745
2746
2747 n =
0;
2748 str = XmStringCreateLocalized(
"Files");
2749 XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
2750 XtSetArg(args[n], XmNleftWidget, data.dirlist); n++;
2751 XtSetArg(args[n], XmNleftOffset,
WIDGET_SPACING); n++;
2752 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
2753 XtSetArg(args[n], XmNbottomWidget, lsDirLabel); n++;
2754 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
2755 XtSetArg(args[n], XmNlabelString, str); n++;
2756 Widget lsFileLabel = XmCreateLabel(data.listform,
"label", args, n);
2757 XtManageChild(lsFileLabel);
2758 XmStringFree(str);
2759
2760 Widget focus =
NULL;
2761 switch(data.selectedview) {
2762 case 1: XtManageChild(data.listform); XtManageChild(data.filelistcontainer); focus = data.filelist;
break;
2763 case 2: XtManageChild(data.listform); XtManageChild(data.gridcontainer); focus = data.grid;
break;
2764 }
2765 if(data.type ==
FILEDIALOG_SAVE) {
2766 focus = data.name;
2767 }
2768 data.pathBar->focus_widget = focus;
2769
2770 if(file->path) {
2771 char *defDir = ParentPath(file->path);
2772 filedialog_update_dir(&data, defDir);
2773 PathBarSetPath(data.pathBar, defDir);
2774 NEditFree(defDir);
2775
2776 XNETextSetString(data.name, FileName(file->path));
2777 }
else {
2778 char *defDirStr = GetDefaultDirectoryStr();
2779 char *defDir = defDirStr ? defDirStr : getenv(
"HOME");
2780
2781 filedialog_update_dir(&data, defDir);
2782 PathBarSetPath(data.pathBar, defDir);
2783 }
2784
2785
2786
2787
2788 keycodeL = XKeysymToKeycode(XtDisplay(dialog), XStringToKeysym(
"L"));
2789 XtGrabKey(
2790 dialog,
2791 keycodeL,
2792 ControlMask,
2793 True,
2794 GrabModeAsync,
2795 GrabModeAsync);
2796 ManageDialogCenteredOnPointer(form);
2797
2798 XmProcessTraversal(focus, XmTRAVERSE_CURRENT);
2799
2800 XtAppContext app = XtWidgetToApplicationContext(dialog);
2801 while(!data.end && !XtAppGetExitFlag(app)) {
2802 XEvent event;
2803 XtAppNextEvent(app, &event);
2804 XtDispatchEvent(&event);
2805 }
2806
2807 LastView = data.selectedview;
2808
2809 if(data.selectedPath && !data.selIsDir && data.status ==
FILEDIALOG_OK) {
2810 file->path = data.selectedPath;
2811 data.selectedPath =
NULL;
2812
2813
2814 LastFilter = XNETextGetString(data.filter);
2815 if(LastFilter) {
2816 if(strlen(LastFilter) ==
0) {
2817 XtFree(LastFilter);
2818 LastFilter =
NULL;
2819 }
2820 }
2821
2822 file->filter = data.selected_filter ? NEditStrdup(data.selected_filter->name) :
NULL;
2823
2824 if(file->extraoptions) {
2825 int encPos;
2826 XtVaGetValues(data.encoding, XmNselectedPosition, &encPos,
NULL);
2827 if(type ==
FILEDIALOG_OPEN) {
2828 if(encPos >
0) {
2829
2830
2831 file->encoding = default_encodings[encPos];
2832 }
2833 }
else {
2834 if(currentEncItem) {
2835
2836
2837 if(encPos >
0) {
2838 file->encoding = default_encodings[encPos];
2839 }
2840 }
else {
2841
2842 file->encoding = default_encodings[encPos+
1];
2843 }
2844 }
2845 }
2846
2847 if(type ==
FILEDIALOG_SAVE) {
2848 int bomVal =
0;
2849 int xattrVal =
0;
2850 int wrapVal =
0;
2851 if(data.bom) {
2852 XtVaGetValues(data.bom, XmNset, &bomVal,
NULL);
2853 }
2854 if(data.xattr) {
2855 XtVaGetValues(data.xattr, XmNset, &xattrVal,
NULL);
2856 }
2857 if(data.wrap) {
2858 XtVaGetValues(data.wrap, XmNset, &wrapVal,
NULL);
2859 }
2860
2861 file->writebom = bomVal;
2862 file->setxattr = xattrVal;
2863 file->addwrap = wrapVal;
2864
2865
2866 if(data.unixFormat) {
2867 int formatVal =
0;
2868 XtVaGetValues(data.unixFormat, XmNset, &formatVal,
NULL);
2869 if(formatVal) {
2870 file->format =
UNIX_FILE_FORMAT;
2871 }
else {
2872 XtVaGetValues(data.dosFormat, XmNset, &formatVal,
NULL);
2873 if(formatVal) {
2874 file->format =
DOS_FILE_FORMAT;
2875 }
else {
2876 XtVaGetValues(data.macFormat, XmNset, &formatVal,
NULL);
2877 if(formatVal) {
2878 file->format =
MAC_FILE_FORMAT;
2879 }
2880 }
2881 }
2882 }
else {
2883 file->format =
0;
2884 }
2885 }
2886 }
else {
2887 data.status =
FILEDIALOG_CANCEL;
2888 if(data.selectedPath) {
2889 NEditFree(data.selectedPath);
2890 }
2891 }
2892
2893 filedialog_cleanup_filedata(&data);
2894 PathBarDestroy(data.pathBar);
2895 if(data.currentPath) {
2896 NEditFree(data.currentPath);
2897 }
2898 XtUnmapWidget(dialog);
2899 XtDestroyWidget(dialog);
2900 return data.status;
2901 }
2902
2903 const char ** FileDialogDefaultEncodings(
void) {
2904 return (
const char **)default_encodings;
2905 }
2906
2907 char* FileDialogGetFilter(
void) {
2908 return NEditStrdup(LastFilter ? LastFilter :
"*");
2909 }
2910
2911 void FileDialogSetFilter(
const char *filterStr) {
2912 NEditFree(LastFilter);
2913 LastFilter = filterStr ? NEditStrdup(filterStr) :
NULL;
2914 }
2915