1 // This code is adapted from 'imageviewer', a demo image viewer found
2 // in the FOX library and written by Jeroen van der Zijp.
3 
4 #include "config.h"
5 #include "i18n.h"
6 
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <sys/stat.h>
10 #include <sys/wait.h>
11 #include <string.h>
12 #include <unistd.h>
13 #include <signal.h>
14 
15 #include <fx.h>
16 #include <fxkeys.h>
17 #include <FXPNGImage.h>
18 #include <FXJPGImage.h>
19 #include <FXTIFImage.h>
20 #include <FXPNGIcon.h>
21 
22 #include "xfedefs.h"
23 #include "icons.h"
24 #include "xfeutils.h"
25 #include "startupnotification.h"
26 #include "FileDialog.h"
27 #include "InputDialog.h"
28 #include "DirHistBox.h"
29 #include "MessageBox.h"
30 #include "FileList.h"
31 #include "XFileImage.h"
32 
33 // Add FOX hacks
34 #include "foxhacks.cpp"
35 #include "clearlooks.cpp"
36 
37 // Global variables
38 char**   args;
39 FXColor  listbackcolor, listforecolor;
40 FXColor  highlightcolor;
41 FXbool   allowPopupScroll = false;
42 FXuint   single_click;
43 FXbool   file_tooltips;
44 FXbool   relative_resize;
45 FXbool   show_pathlink;
46 FXbool   save_win_pos;
47 FXString homedir;
48 FXString xdgconfighome;
49 FXString xdgdatahome;
50 FXbool   xim_used = false;
51 
52 // Main window (not used but necessary for compilation)
53 FXMainWindow* mainWindow = NULL;
54 
55 // Scaling factors for the UI
56 extern double scalefrac;
57 
58 // Hand cursor replacement (integer scaling factor = 1)
59 #define hand1_width     32
60 #define hand1_height    32
61 #define hand1_x_hot     6
62 #define hand1_y_hot     1
63 static const FXuchar hand1_bits[] =
64 {
65    0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00,
66    0x90, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x90, 0x03, 0x00, 0x00,
67    0x90, 0x1c, 0x00, 0x00, 0x10, 0xe4, 0x00, 0x00, 0x1c, 0x20, 0x01, 0x00,
68    0x12, 0x00, 0x01, 0x00, 0x12, 0x00, 0x01, 0x00, 0x92, 0x24, 0x01, 0x00,
69    0x82, 0x24, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
70    0x02, 0x00, 0x01, 0x00, 0xfc, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
71    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
72    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
73    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
74    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
75    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
76 };
77 
78 static const FXuchar hand1_mask_bits[] =
79 {
80    0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00,
81    0xf0, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00,
82    0xf0, 0x1f, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00,
83    0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00,
84    0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00,
85    0xfe, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
86    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
87    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
88    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
89    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
90    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
91 };
92 
93 
94 // Hand cursor replacement (integer scaling factor = 2)
95 #define hand2_width     32
96 #define hand2_height    32
97 #define hand2_x_hot     6
98 #define hand2_y_hot     1
99 static const FXuchar hand2_bits[] =
100 {
101    0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00,
102    0x60, 0x06, 0x00, 0x00, 0x20, 0x06, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00,
103    0x20, 0x1e, 0x00, 0x00, 0x60, 0x3e, 0x00, 0x00, 0x20, 0xe2, 0x03, 0x00,
104    0x60, 0x62, 0x1e, 0x00, 0x38, 0x00, 0x74, 0x00, 0x7c, 0x00, 0x60, 0x00,
105    0x24, 0x00, 0x40, 0x00, 0x64, 0x00, 0x60, 0x00, 0x26, 0x00, 0x40, 0x00,
106    0x26, 0x22, 0x62, 0x00, 0x06, 0x22, 0x42, 0x00, 0x06, 0x00, 0x60, 0x00,
107    0x06, 0x00, 0x40, 0x00, 0x06, 0x00, 0x60, 0x00, 0x04, 0x00, 0x60, 0x00,
108    0xfc, 0xff, 0x3f, 0x00, 0xf0, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00,
109    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
110    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
111    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
112 };
113 
114 static const FXuchar hand2_mask_bits[] =
115 {
116    0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00,
117    0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00,
118    0xe0, 0x1f, 0x00, 0x00, 0xe0, 0x3f, 0x00, 0x00, 0xe0, 0xff, 0x03, 0x00,
119    0xe0, 0xff, 0x1f, 0x00, 0xf8, 0xff, 0x7f, 0x00, 0xfc, 0xff, 0x7f, 0x00,
120    0xfc, 0xff, 0x7f, 0x00, 0xfc, 0xff, 0x7f, 0x00, 0xfe, 0xff, 0x7f, 0x00,
121    0xfe, 0xff, 0x7f, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0xfe, 0xff, 0x7f, 0x00,
122    0xfe, 0xff, 0x7f, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0xfc, 0xff, 0x7f, 0x00,
123    0xfc, 0xff, 0x3f, 0x00, 0xf0, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00,
124    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
125    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
126    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
127 };
128 
129 
130 // Hand cursor replacement (integer scaling factor = 3 or more)
131 #define hand3_width     32
132 #define hand3_height    32
133 #define hand3_x_hot     6
134 #define hand3_y_hot     1
135 static const FXuchar hand3_bits[] =
136 {
137    0x80, 0x1f, 0x00, 0x00, 0xc0, 0x3f, 0x00, 0x00, 0xc0, 0x30, 0x00, 0x00,
138    0xc0, 0x30, 0x00, 0x00, 0xc0, 0x30, 0x00, 0x00, 0xc0, 0x30, 0x00, 0x00,
139    0xc0, 0x30, 0x00, 0x00, 0xc0, 0x30, 0x00, 0x00, 0xc0, 0xf0, 0x03, 0x00,
140    0xc0, 0xf0, 0x07, 0x00, 0xc0, 0x30, 0xfe, 0x00, 0xc0, 0x10, 0xfe, 0x01,
141    0xc0, 0x10, 0x8c, 0x3f, 0xc0, 0x10, 0x04, 0x7f, 0xfc, 0x00, 0x04, 0xe1,
142    0xfe, 0x00, 0x04, 0xc1, 0xc6, 0x00, 0x04, 0xc0, 0xc6, 0x00, 0x00, 0xc0,
143    0xc6, 0x00, 0x00, 0xc0, 0xc3, 0x00, 0x00, 0xc0, 0xc3, 0x00, 0x00, 0xc0,
144    0xc3, 0x10, 0x04, 0xc1, 0x03, 0x10, 0x04, 0xc1, 0x03, 0x10, 0x04, 0xc1,
145    0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0,
146    0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0xe0,
147    0xfe, 0xff, 0xff, 0x7f, 0xfc, 0xff, 0xff, 0x3f
148 };
149 
150 static const FXuchar hand3_mask_bits[] =
151 {
152    0x80, 0x1f, 0x00, 0x00, 0xc0, 0x3f, 0x00, 0x00, 0xc0, 0x3f, 0x00, 0x00,
153    0xc0, 0x3f, 0x00, 0x00, 0xc0, 0x3f, 0x00, 0x00, 0xc0, 0x3f, 0x00, 0x00,
154    0xc0, 0x3f, 0x00, 0x00, 0xc0, 0x3f, 0x00, 0x00, 0xc0, 0xff, 0x03, 0x00,
155    0xc0, 0xff, 0x07, 0x00, 0xc0, 0xff, 0xff, 0x00, 0xc0, 0xff, 0xff, 0x01,
156    0xc0, 0xff, 0xff, 0x3f, 0xc0, 0xff, 0xff, 0x7f, 0xfc, 0xff, 0xff, 0xff,
157    0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff,
158    0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
159    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
160    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
161    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
162    0xfe, 0xff, 0xff, 0x7f, 0xfc, 0xff, 0xff, 0x3f
163 };
164 
165 
166 // Predefined zoom factors
167 #define NB_ZOOM    24
168 double zoomtab[NB_ZOOM] =
169 {
170     0.01, 0.025, 0.05, 0.075, 0.10, 0.15, 0.20, 0.30, 0.50, 0.75, 1, \
171     1.5, 2, 3, 4, 5, 7.5, 10, 15, 20, 30, 50, 75, 100
172 };
173 #define ZOOM_100       10
174 
175 // Maximum image size (in pixels) for zooming in
176 #define MAX_IMGSIZE    5120
177 
178 // Patterns for supported image formats
179 const char* patterns[] =
180 {
181     _("All Files"), "*",
182     _("GIF Image"), "*.gif",
183     _("BMP Image"), "*.bmp",
184     _("XPM Image"), "*.xpm",
185     _("PCX Image"), "*.pcx",
186     _("ICO Image"), "*.ico",
187     _("RGB Image"), "*.rgb",
188     _("XBM Image"), "*.xbm",
189     _("TARGA Image"), "*.tga",
190     _("PPM Image"), "*.ppm",
191     _("PNG Image"), "*.png",
192     _("JPEG Image"), "*.jpg",
193     _("JPEG Image"), "*.jpeg",
194     _("TIFF Image"), "*.tif",
195     _("TIFF Image"), "*.tiff",
196     NULL
197 };
198 
199 
200 const FXString imgpatterns = "*.gif,*.bmp,*.xpm,*.pcx,*.ico,*.rgb,*.xbm,*.tga,*.ppm,*.png,*.jpg,*.jpeg,*.tif,*.tiff";
201 
202 
203 // Helper function to draw a toolbar separator
toolbarSeparator(FXToolBar * tb)204 void toolbarSeparator(FXToolBar* tb)
205 {
206 #define SEP_SPACE_TB    1
207     new FXFrame(tb, LAYOUT_CENTER_Y|LAYOUT_LEFT|LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT, 0, 0, SEP_SPACE_TB);
208     new FXVerticalSeparator(tb, LAYOUT_SIDE_TOP|LAYOUT_CENTER_Y|SEPARATOR_GROOVE|LAYOUT_FILL_Y);
209     new FXFrame(tb, LAYOUT_CENTER_Y|LAYOUT_LEFT|LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT, 0, 0, SEP_SPACE_TB);
210 }
211 
212 
213 // Helper function to draw a separator in an horizontal frame
hframeSeparator(FXHorizontalFrame * hframe)214 void hframeSeparator(FXHorizontalFrame* hframe)
215 {
216 #define SEP_SPACE_HF    5
217     new FXFrame(hframe, LAYOUT_CENTER_Y|LAYOUT_LEFT|LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT, 0, 0, SEP_SPACE_HF);
218     new FXVerticalSeparator(hframe, LAYOUT_SIDE_TOP|LAYOUT_CENTER_Y|SEPARATOR_GROOVE|LAYOUT_FILL_Y);
219     new FXFrame(hframe, LAYOUT_CENTER_Y|LAYOUT_LEFT|LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT, 0, 0, SEP_SPACE_HF);
220 }
221 
222 
223 // Map
224 FXDEFMAP(XFileImage) XFileImageMap[] =
225 {
226     FXMAPFUNC(SEL_COMMAND, XFileImage::ID_ABOUT, XFileImage::onCmdAbout),
227     FXMAPFUNC(SEL_COMMAND, XFileImage::ID_OPEN, XFileImage::onCmdOpen),
228     FXMAPFUNC(SEL_UPDATE, XFileImage::ID_TITLE, XFileImage::onUpdTitle),
229     FXMAPFUNC(SEL_SIGNAL, XFileImage::ID_HARVEST, XFileImage::onSigHarvest),
230     FXMAPFUNC(SEL_COMMAND, XFileImage::ID_QUIT, XFileImage::onCmdQuit),
231     FXMAPFUNC(SEL_SIGNAL, XFileImage::ID_QUIT, XFileImage::onCmdQuit),
232     FXMAPFUNC(SEL_CLOSE, XFileImage::ID_TITLE, XFileImage::onCmdQuit),
233     FXMAPFUNC(SEL_COMMAND, XFileImage::ID_RESTART, XFileImage::onCmdRestart),
234     FXMAPFUNC(SEL_COMMAND, XFileImage::ID_TOGGLE_FILELIST_BEFORE, XFileImage::onCmdToggleFileListBefore),
235     FXMAPFUNC(SEL_COMMAND, XFileImage::ID_HORZ_PANELS, XFileImage::onCmdHorzVertPanels),
236     FXMAPFUNC(SEL_COMMAND, XFileImage::ID_VERT_PANELS, XFileImage::onCmdHorzVertPanels),
237     FXMAPFUNC(SEL_DOUBLECLICKED, XFileImage::ID_FILELIST, XFileImage::onCmdItemDoubleClicked),
238     FXMAPFUNC(SEL_CLICKED, XFileImage::ID_FILELIST, XFileImage::onCmdItemClicked),
239     FXMAPFUNC(SEL_KEYPRESS, 0, XFileImage::onKeyPress),
240     FXMAPFUNC(SEL_KEYRELEASE, 0, XFileImage::onKeyRelease),
241     FXMAPFUNC(SEL_COMMAND, XFileImage::ID_RECENTFILE, XFileImage::onCmdRecentFile),
242     FXMAPFUNC(SEL_COMMAND, XFileImage::ID_TOGGLE_HIDDEN, XFileImage::onCmdToggleHidden),
243     FXMAPFUNC(SEL_COMMAND, XFileImage::ID_TOGGLE_THUMBNAILS, XFileImage::onCmdToggleThumbnails),
244     FXMAPFUNC(SEL_COMMAND, XFileImage::ID_SHOW_DETAILS, XFileImage::onCmdShowDetails),
245     FXMAPFUNC(SEL_COMMAND, XFileImage::ID_SHOW_MINI_ICONS, XFileImage::onCmdShowMini),
246     FXMAPFUNC(SEL_COMMAND, XFileImage::ID_SHOW_BIG_ICONS, XFileImage::onCmdShowBig),
247     FXMAPFUNC(SEL_COMMAND, XFileImage::ID_ROTATE_90, XFileImage::onCmdRotate),
248     FXMAPFUNC(SEL_COMMAND, XFileImage::ID_ROTATE_270, XFileImage::onCmdRotate),
249     FXMAPFUNC(SEL_COMMAND, XFileImage::ID_MIRROR_HOR, XFileImage::onCmdMirror),
250     FXMAPFUNC(SEL_COMMAND, XFileImage::ID_MIRROR_VER, XFileImage::onCmdMirror),
251     FXMAPFUNC(SEL_COMMAND, XFileImage::ID_ZOOM_IN, XFileImage::onCmdZoomIn),
252     FXMAPFUNC(SEL_COMMAND, XFileImage::ID_ZOOM_OUT, XFileImage::onCmdZoomOut),
253     FXMAPFUNC(SEL_COMMAND, XFileImage::ID_ZOOM_100, XFileImage::onCmdZoom100),
254     FXMAPFUNC(SEL_COMMAND, XFileImage::ID_ZOOM_WIN, XFileImage::onCmdZoomWin),
255     FXMAPFUNC(SEL_COMMAND, XFileImage::ID_PRINT, XFileImage::onCmdPrint),
256     FXMAPFUNC(SEL_COMMAND, XFileImage::ID_DIR_UP, XFileImage::onCmdDirUp),
257     FXMAPFUNC(SEL_UPDATE, XFileImage::ID_DIR_UP, XFileImage::onUpdDirUp),
258     FXMAPFUNC(SEL_COMMAND, XFileImage::ID_DIR_BACK, XFileImage::onCmdDirBack),
259     FXMAPFUNC(SEL_UPDATE, XFileImage::ID_DIR_BACK, XFileImage::onUpdDirBack),
260     FXMAPFUNC(SEL_COMMAND, XFileImage::ID_DIR_FORWARD, XFileImage::onCmdDirForward),
261     FXMAPFUNC(SEL_UPDATE, XFileImage::ID_DIR_FORWARD, XFileImage::onUpdDirForward),
262     FXMAPFUNC(SEL_COMMAND, XFileImage::ID_DIR_BACK_HIST, XFileImage::onCmdDirBackHist),
263     FXMAPFUNC(SEL_UPDATE, XFileImage::ID_DIR_BACK_HIST, XFileImage::onUpdDirBackHist),
264     FXMAPFUNC(SEL_COMMAND, XFileImage::ID_DIR_FORWARD_HIST, XFileImage::onCmdDirForwardHist),
265     FXMAPFUNC(SEL_UPDATE, XFileImage::ID_DIR_FORWARD_HIST, XFileImage::onUpdDirForwardHist),
266     FXMAPFUNC(SEL_COMMAND, XFileImage::ID_GO_HOME, XFileImage::onCmdHome),
267     FXMAPFUNC(SEL_UPDATE, XFileImage::ID_PRINT, XFileImage::onUpdImage),
268     FXMAPFUNC(SEL_UPDATE, XFileImage::ID_ROTATE_90, XFileImage::onUpdImage),
269     FXMAPFUNC(SEL_UPDATE, XFileImage::ID_ROTATE_270, XFileImage::onUpdImage),
270     FXMAPFUNC(SEL_UPDATE, XFileImage::ID_MIRROR_HOR, XFileImage::onUpdImage),
271     FXMAPFUNC(SEL_UPDATE, XFileImage::ID_MIRROR_VER, XFileImage::onUpdImage),
272     FXMAPFUNC(SEL_UPDATE, XFileImage::ID_ZOOM_IN, XFileImage::onUpdImage),
273     FXMAPFUNC(SEL_UPDATE, XFileImage::ID_ZOOM_OUT, XFileImage::onUpdImage),
274     FXMAPFUNC(SEL_UPDATE, XFileImage::ID_ZOOM_100, XFileImage::onUpdImage),
275     FXMAPFUNC(SEL_UPDATE, XFileImage::ID_ZOOM_WIN, XFileImage::onUpdImage),
276     FXMAPFUNC(SEL_UPDATE, XFileImage::ID_SHOW_BIG_ICONS, XFileImage::onUpdFileView),
277     FXMAPFUNC(SEL_UPDATE, XFileImage::ID_SHOW_MINI_ICONS, XFileImage::onUpdFileView),
278     FXMAPFUNC(SEL_UPDATE, XFileImage::ID_SHOW_DETAILS, XFileImage::onUpdFileView),
279     FXMAPFUNC(SEL_UPDATE, XFileImage::ID_TOGGLE_HIDDEN, XFileImage::onUpdToggleHidden),
280     FXMAPFUNC(SEL_UPDATE, XFileImage::ID_TOGGLE_FILELIST_BEFORE, XFileImage::onUpdToggleFileListBefore),
281     FXMAPFUNC(SEL_UPDATE, XFileImage::ID_TOGGLE_THUMBNAILS, XFileImage::onUpdToggleThumbnails),
282     FXMAPFUNC(SEL_COMMAND, XFileImage::ID_TOGGLE_FIT_WIN, XFileImage::onCmdToggleFitWin),
283     FXMAPFUNC(SEL_COMMAND, XFileImage::ID_TOGGLE_FILTER_IMAGES, XFileImage::onCmdToggleFilterImages),
284     FXMAPFUNC(SEL_UPDATE, XFileImage::ID_TOGGLE_FIT_WIN, XFileImage::onUpdToggleFitWin),
285     FXMAPFUNC(SEL_UPDATE, XFileImage::ID_TOGGLE_FILTER_IMAGES, XFileImage::onUpdToggleFilterImages),
286     FXMAPFUNC(SEL_UPDATE, XFileImage::ID_HORZ_PANELS, XFileImage::onUpdHorzVertPanels),
287     FXMAPFUNC(SEL_UPDATE, XFileImage::ID_VERT_PANELS, XFileImage::onUpdHorzVertPanels),
288     FXMAPFUNC(SEL_COMMAND, XFileImage::ID_GO_HOME, XFileImage::onCmdHome),
289     FXMAPFUNC(SEL_COMMAND, XFileImage::ID_GO_WORK, XFileImage::onCmdWork),
290     FXMAPFUNC(SEL_RIGHTBUTTONRELEASE, XFileImage::ID_FILELIST, XFileImage::onCmdPopupMenu),
291     FXMAPFUNC(SEL_COMMAND, XFileImage::ID_POPUP_MENU, XFileImage::onCmdPopupMenu),
292 };
293 
294 
295 // Object implementation
FXIMPLEMENT(XFileImage,FXMainWindow,XFileImageMap,ARRAYNUMBER (XFileImageMap))296 FXIMPLEMENT(XFileImage, FXMainWindow, XFileImageMap, ARRAYNUMBER(XFileImageMap))
297 
298 
299 // Make some windows
300 XFileImage::XFileImage(FXApp* a, FXbool smoothscroll) : FXMainWindow(a, "Xfi ", NULL, NULL, DECOR_ALL)
301 {
302     setIcon(xfiicon);
303 
304     FXButton* btn = NULL;
305     FXHotKey  hotkey;
306     FXString  key;
307 
308     setTarget(this);
309     setSelector(ID_TITLE);
310 
311     // Make menu bar
312     menubar = new FXMenuBar(this, LAYOUT_DOCK_NEXT|LAYOUT_SIDE_TOP|LAYOUT_FILL_X|FRAME_RAISED);
313 
314     // Sites where to dock
315     FXDockSite* topdock = new FXDockSite(this, LAYOUT_SIDE_TOP|LAYOUT_FILL_X);
316     new FXDockSite(this, LAYOUT_SIDE_BOTTOM|LAYOUT_FILL_X);
317     new FXDockSite(this, LAYOUT_SIDE_LEFT|LAYOUT_FILL_Y);
318     new FXDockSite(this, LAYOUT_SIDE_RIGHT|LAYOUT_FILL_Y);
319 
320     // Tool bar
321     FXToolBarShell* dragshell1 = new FXToolBarShell(this, FRAME_RAISED);
322     toolbar = new FXToolBar(topdock, dragshell1, LAYOUT_DOCK_NEXT|LAYOUT_SIDE_TOP|LAYOUT_FILL_X|LAYOUT_FILL_Y|FRAME_RAISED);
323     new FXToolBarGrip(toolbar, toolbar, FXToolBar::ID_TOOLBARGRIP, TOOLBARGRIP_DOUBLE);
324 
325     // File menu
326     filemenu = new FXMenuPane(this);
327     new FXMenuTitle(menubar, _("&File"), NULL, filemenu);
328 
329     // Image Menu
330     imagemenu = new FXMenuPane(this);
331     new FXMenuTitle(menubar, _("&Image"), NULL, imagemenu);
332 
333     // View menu
334     viewmenu = new FXMenuPane(this);
335     new FXMenuTitle(menubar, _("&View"), NULL, viewmenu);
336 
337     // Preferences Menu
338     prefsmenu = new FXMenuPane(this);
339     new FXMenuTitle(menubar, _("&Preferences"), NULL, prefsmenu);
340 
341     // Help menu
342     helpmenu = new FXMenuPane(this);
343     new FXMenuTitle(menubar, _("&Help"), NULL, helpmenu);
344 
345     // Splitter
346     FXVerticalFrame* vframe = new FXVerticalFrame(this, LAYOUT_FILL_X|LAYOUT_FILL_Y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
347 
348     // Set order of the file list and image widgets
349     filelistbefore = getApp()->reg().readUnsignedEntry("OPTIONS", "filelist_before", false);
350     if (filelistbefore)
351     {
352         splitter = new FXSplitter(vframe, LAYOUT_SIDE_TOP|LAYOUT_FILL_X|LAYOUT_FILL_Y|SPLITTER_TRACKING|SPLITTER_VERTICAL);
353         filebox = new FXVerticalFrame(splitter, LAYOUT_FILL_X|LAYOUT_FILL_Y|FRAME_NONE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
354         imageview = new FXImageView(splitter, NULL, NULL, 0, LAYOUT_FILL_X|LAYOUT_FILL_Y|FRAME_SUNKEN);
355     }
356     else
357     {
358         splitter = new FXSplitter(vframe, LAYOUT_SIDE_TOP|LAYOUT_FILL_X|LAYOUT_FILL_Y|SPLITTER_TRACKING|SPLITTER_VERTICAL|SPLITTER_REVERSED);
359         imageview = new FXImageView(splitter, NULL, NULL, 0, LAYOUT_FILL_X|LAYOUT_FILL_Y|FRAME_SUNKEN);
360         filebox = new FXVerticalFrame(splitter, LAYOUT_FILL_X|LAYOUT_FILL_Y|FRAME_NONE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
361     }
362 
363     // Stack panels horizontally or vertically
364     vertpanels = getApp()->reg().readUnsignedEntry("OPTIONS", "vert_panels", false);
365     if (vertpanels)
366     {
367         splitter->setSplitterStyle(splitter->getSplitterStyle()&~SPLITTER_VERTICAL);
368     }
369     else
370     {
371         splitter->setSplitterStyle(splitter->getSplitterStyle()|SPLITTER_VERTICAL);
372     }
373 
374     // Container for the action buttons
375     FXHorizontalFrame* buttons = new FXHorizontalFrame(filebox, LAYOUT_SIDE_TOP|LAYOUT_FILL_X|FRAME_RAISED, 0, 0, 0, 0, 5, 5, 5, 5, 0, 0);
376 
377     // Container for the path linker
378     FXHorizontalFrame* pathframe = new FXHorizontalFrame(filebox, LAYOUT_FILL_X|FRAME_RAISED, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
379 
380     // File list
381     FXuint options;
382     if (smoothscroll)
383     {
384         options = LAYOUT_FILL_X|LAYOUT_FILL_Y|_ICONLIST_MINI_ICONS|_ICONLIST_BROWSESELECT;
385     }
386     else
387     {
388         options = LAYOUT_FILL_X|LAYOUT_FILL_Y|_ICONLIST_MINI_ICONS|_ICONLIST_BROWSESELECT|SCROLLERS_DONT_TRACK;
389     }
390 
391     thumbnails = getApp()->reg().readUnsignedEntry("OPTIONS", "thumbnails", 0);
392     filelist = new FileList(this, filebox, this, ID_FILELIST, thumbnails, options);
393     filelist->setTextColor(listforecolor);
394     filelist->setBackColor(listbackcolor);
395     filelist->setHeaderSize(0, getApp()->reg().readUnsignedEntry("OPTIONS", "name_size", 200));
396     filelist->setHeaderSize(1, getApp()->reg().readUnsignedEntry("OPTIONS", "size_size", 60));
397     filelist->setHeaderSize(2, getApp()->reg().readUnsignedEntry("OPTIONS", "type_size", 100));
398     filelist->setHeaderSize(3, getApp()->reg().readUnsignedEntry("OPTIONS", "ext_size", 100));
399     filelist->setHeaderSize(4, getApp()->reg().readUnsignedEntry("OPTIONS", "modd_size", 150));
400     filelist->setHeaderSize(5, getApp()->reg().readUnsignedEntry("OPTIONS", "user_size", 50));
401     filelist->setHeaderSize(6, getApp()->reg().readUnsignedEntry("OPTIONS", "grou_size", 50));
402     filelist->setHeaderSize(7, getApp()->reg().readUnsignedEntry("OPTIONS", "attr_size", 100));
403 
404     // Action buttons
405     new FXFrame(buttons, LAYOUT_FIX_WIDTH, 0, 0, 4, 1);
406 
407     key = getApp()->reg().readStringEntry("KEYBINDINGS", "go_back", "Ctrl-Backspace");
408     btn = new FXButton(buttons, TAB+_("Go to previous folder")+PARS(key), dirbackicon, this, ID_DIR_BACK, BUTTON_TOOLBAR|FRAME_RAISED|LAYOUT_CENTER_Y|LAYOUT_LEFT);
409     hotkey = _parseAccel(key);
410     btn->addHotKey(hotkey);
411     btnbackhist = new FXArrowButton(buttons, this, ID_DIR_BACK_HIST, LAYOUT_FILL_Y|FRAME_RAISED|FRAME_THICK|ARROW_DOWN|ARROW_TOOLBAR);
412 
413     key = getApp()->reg().readStringEntry("KEYBINDINGS", "go_forward", "Shift-Backspace");
414     btn = new FXButton(buttons, TAB+_("Go to next folder")+PARS(key), dirforwardicon, this, ID_DIR_FORWARD, BUTTON_TOOLBAR|FRAME_RAISED|LAYOUT_CENTER_Y|LAYOUT_LEFT);
415     hotkey = _parseAccel(key);
416     btn->addHotKey(hotkey);
417     btnforwardhist = new FXArrowButton(buttons, this, ID_DIR_FORWARD_HIST, LAYOUT_FILL_Y|FRAME_RAISED|FRAME_THICK|ARROW_DOWN|ARROW_TOOLBAR);
418 
419     key = getApp()->reg().readStringEntry("KEYBINDINGS", "go_up", "Backspace");
420     btn = new FXButton(buttons, TAB+_("Go to parent folder")+PARS(key), dirupicon, this, ID_DIR_UP, BUTTON_TOOLBAR|FRAME_RAISED|LAYOUT_CENTER_Y|LAYOUT_LEFT);
421     hotkey = _parseAccel(key);
422     btn->addHotKey(hotkey);
423 
424     // Separator
425     hframeSeparator(buttons);
426 
427     key = getApp()->reg().readStringEntry("KEYBINDINGS", "go_home", "Ctrl-H");
428     new FXButton(buttons, TAB+_("Go to home folder")+PARS(key), homeicon, this, ID_GO_HOME, BUTTON_TOOLBAR|FRAME_RAISED|LAYOUT_CENTER_Y|LAYOUT_LEFT);
429     hotkey = _parseAccel(key);
430     btn->addHotKey(hotkey);
431 
432     key = getApp()->reg().readStringEntry("KEYBINDINGS", "go_work", "Shift-F2");
433     new FXButton(buttons, TAB+_("Go to working folder")+PARS(key), workicon, this, ID_GO_WORK, BUTTON_TOOLBAR|FRAME_RAISED|LAYOUT_CENTER_Y|LAYOUT_LEFT);
434     hotkey = _parseAccel(key);
435     btn->addHotKey(hotkey);
436 
437     // Separator
438     hframeSeparator(buttons);
439 
440     // Switch display modes
441     key = getApp()->reg().readStringEntry("KEYBINDINGS", "big_icons", "F10");
442     btn = new FXButton(buttons, TAB+_("Big icon list")+PARS(key), bigiconsicon, this, ID_SHOW_BIG_ICONS, BUTTON_TOOLBAR|LAYOUT_CENTER_Y|LAYOUT_LEFT|ICON_BEFORE_TEXT|FRAME_RAISED);
443     hotkey = _parseAccel(key);
444     btn->addHotKey(hotkey);
445 
446     key = getApp()->reg().readStringEntry("KEYBINDINGS", "small_icons", "F11");
447     btn = new FXButton(buttons, TAB+_("Small icon list")+PARS(key), smalliconsicon, this, ID_SHOW_MINI_ICONS, BUTTON_TOOLBAR|LAYOUT_CENTER_Y|LAYOUT_LEFT|ICON_BEFORE_TEXT|FRAME_RAISED);
448     hotkey = _parseAccel(key);
449     btn->addHotKey(hotkey);
450 
451     key = getApp()->reg().readStringEntry("KEYBINDINGS", "detailed_file_list", "F12");
452     btn = new FXButton(buttons, TAB+_("Detailed file list")+PARS(key), detailsicon, this, ID_SHOW_DETAILS, BUTTON_TOOLBAR|LAYOUT_CENTER_Y|LAYOUT_LEFT|ICON_BEFORE_TEXT|FRAME_RAISED);
453     hotkey = _parseAccel(key);
454     btn->addHotKey(hotkey);
455 
456     // Separator
457     hframeSeparator(buttons);
458 
459     // Vertical panels
460     key = getApp()->reg().readStringEntry("KEYBINDINGS", "vert_panels", "Ctrl-Shift-F1");
461     btn = new FXButton(buttons, TAB+_("Vertical panels")+PARS(key), vertpanelsicon, this, XFileImage::ID_VERT_PANELS, BUTTON_TOOLBAR|FRAME_RAISED|LAYOUT_CENTER_Y|LAYOUT_LEFT|ICON_BEFORE_TEXT);
462     hotkey = _parseAccel(key);
463     btn->addHotKey(hotkey);
464 
465     // Horizontal panels
466     key = getApp()->reg().readStringEntry("KEYBINDINGS", "horz_panels", "Ctrl-Shift-F2");
467     btn = new FXButton(buttons, TAB+_("Horizontal panels")+PARS(key), horzpanelsicon, this, XFileImage::ID_HORZ_PANELS, BUTTON_TOOLBAR|FRAME_RAISED|LAYOUT_CENTER_Y|LAYOUT_LEFT|ICON_BEFORE_TEXT);
468     hotkey = _parseAccel(key);
469     btn->addHotKey(hotkey);
470 
471     // Panel title
472     pathtext = new TextLabel(pathframe, 0, this, 0, LAYOUT_FILL_X|LAYOUT_FILL_Y);
473     pathtext->setBackColor(getApp()->getBaseColor());
474 
475     // Path linker
476     pathlink = new PathLinker(pathframe, filelist, NULL, LAYOUT_FILL_X);
477 
478     // Status bar
479     statusbar = new FXHorizontalFrame(vframe, JUSTIFY_LEFT|LAYOUT_FILL_X|FRAME_RAISED, 0, 0, 0, 0, 3, 3, 0, 0);
480 
481     // Read and set sort function for file list
482     FXString sort_func = getApp()->reg().readStringEntry("OPTIONS", "sort_func", "ascendingCase");
483     if (sort_func == "ascendingCase")
484     {
485         filelist->setSortFunc(filelist->ascendingCase);
486     }
487     if (sort_func == "ascendingCaseMix")
488     {
489         filelist->setSortFunc(filelist->ascendingCaseMix);
490     }
491     else if (sort_func == "descendingCase")
492     {
493         filelist->setSortFunc(filelist->descendingCase);
494     }
495     else if (sort_func == "descendingCaseMix")
496     {
497         filelist->setSortFunc(filelist->descendingCaseMix);
498     }
499     else if (sort_func == "ascending")
500     {
501         filelist->setSortFunc(filelist->ascending);
502     }
503     else if (sort_func == "ascendingMix")
504     {
505         filelist->setSortFunc(filelist->ascendingMix);
506     }
507     else if (sort_func == "descending")
508     {
509         filelist->setSortFunc(filelist->descending);
510     }
511     else if (sort_func == "descendingMix")
512     {
513         filelist->setSortFunc(filelist->descendingMix);
514     }
515     else if (sort_func == "ascendingSize")
516     {
517         filelist->setSortFunc(filelist->ascendingSize);
518     }
519     else if (sort_func == "ascendingSizeMix")
520     {
521         filelist->setSortFunc(filelist->ascendingSizeMix);
522     }
523     else if (sort_func == "descendingSize")
524     {
525         filelist->setSortFunc(filelist->descendingSize);
526     }
527     else if (sort_func == "descendingSizeMix")
528     {
529         filelist->setSortFunc(filelist->descendingSizeMix);
530     }
531     else if (sort_func == "ascendingType")
532     {
533         filelist->setSortFunc(filelist->ascendingType);
534     }
535     else if (sort_func == "ascendingTypeMix")
536     {
537         filelist->setSortFunc(filelist->ascendingTypeMix);
538     }
539     else if (sort_func == "descendingType")
540     {
541         filelist->setSortFunc(filelist->descendingType);
542     }
543     else if (sort_func == "descendingTypeMix")
544     {
545         filelist->setSortFunc(filelist->descendingTypeMix);
546     }
547     else if (sort_func == "ascendingExt")
548     {
549         filelist->setSortFunc(filelist->ascendingExt);
550     }
551     else if (sort_func == "ascendingExtMix")
552     {
553         filelist->setSortFunc(filelist->ascendingExtMix);
554     }
555     else if (sort_func == "descendingExt")
556     {
557         filelist->setSortFunc(filelist->descendingExt);
558     }
559     else if (sort_func == "descendingExtMix")
560     {
561         filelist->setSortFunc(filelist->descendingExtMix);
562     }
563     else if (sort_func == "ascendingTime")
564     {
565         filelist->setSortFunc(filelist->ascendingTime);
566     }
567     else if (sort_func == "ascendingTimeMix")
568     {
569         filelist->setSortFunc(filelist->ascendingTimeMix);
570     }
571     else if (sort_func == "descendingTime")
572     {
573         filelist->setSortFunc(filelist->descendingTime);
574     }
575     else if (sort_func == "descendingTimeMix")
576     {
577         filelist->setSortFunc(filelist->descendingTimeMix);
578     }
579     else if (sort_func == "ascendingUser")
580     {
581         filelist->setSortFunc(filelist->ascendingUser);
582     }
583     else if (sort_func == "ascendingUserMix")
584     {
585         filelist->setSortFunc(filelist->ascendingUserMix);
586     }
587     else if (sort_func == "descendingUser")
588     {
589         filelist->setSortFunc(filelist->descendingUser);
590     }
591     else if (sort_func == "descendingUserMix")
592     {
593         filelist->setSortFunc(filelist->descendingUserMix);
594     }
595     else if (sort_func == "ascendingGroup")
596     {
597         filelist->setSortFunc(filelist->ascendingGroup);
598     }
599     else if (sort_func == "ascendingGroupMix")
600     {
601         filelist->setSortFunc(filelist->ascendingGroupMix);
602     }
603     else if (sort_func == "descendingGroup")
604     {
605         filelist->setSortFunc(filelist->descendingGroup);
606     }
607     else if (sort_func == "descendingGroupMix")
608     {
609         filelist->setSortFunc(filelist->descendingGroupMix);
610     }
611     else if (sort_func == "ascendingPerm")
612     {
613         filelist->setSortFunc(filelist->ascendingPerm);
614     }
615     else if (sort_func == "ascendingPermMix")
616     {
617         filelist->setSortFunc(filelist->ascendingPermMix);
618     }
619     else if (sort_func == "descendingPerm")
620     {
621         filelist->setSortFunc(filelist->descendingPerm);
622     }
623     else if (sort_func == "descendingPermMix")
624     {
625         filelist->setSortFunc(filelist->descendingPermMix);
626     }
627 
628     // Single click navigation
629     if (single_click == SINGLE_CLICK_DIR_FILE)
630     {
631         filelist->setDefaultCursor(getApp()->getDefaultCursor(DEF_HAND_CURSOR));
632     }
633 
634     // Status bar buttons
635     key = getApp()->reg().readStringEntry("KEYBINDINGS", "hidden_files", "Ctrl-F6");
636     new FXToggleButton(statusbar, TAB+_("Show hidden files")+PARS(key), TAB+_("Hide hidden files")+PARS(key), showhiddenicon, hidehiddenicon, this->filelist,
637                        FileList::ID_TOGGLE_HIDDEN, BUTTON_TOOLBAR|LAYOUT_LEFT|ICON_BEFORE_TEXT);
638 
639     key = getApp()->reg().readStringEntry("KEYBINDINGS", "thumbnails", "Ctrl-F7");
640     new FXToggleButton(statusbar, TAB+_("Show thumbnails")+PARS(key), TAB+_("Hide thumbnails")+PARS(key), showthumbicon, hidethumbicon, this->filelist,
641                        FileList::ID_TOGGLE_THUMBNAILS, BUTTON_TOOLBAR|LAYOUT_LEFT|ICON_BEFORE_TEXT);
642 
643     new FXStatusBar(statusbar, LAYOUT_SIDE_BOTTOM|LAYOUT_FILL_X);
644     new FXDragCorner(statusbar);
645 
646     // Toolbar button: Open file
647     key = getApp()->reg().readStringEntry("KEYBINDINGS", "open", "Ctrl-O");
648     new FXButton(toolbar, TAB+_("Open")+PARS(key)+TAB+_("Open image file.")+PARS(key), fileopenicon, this, ID_OPEN, ICON_ABOVE_TEXT|BUTTON_TOOLBAR|FRAME_RAISED);
649 
650     // Toolbar button: Print
651     key = getApp()->reg().readStringEntry("KEYBINDINGS", "print", "Ctrl-P");
652     new FXButton(toolbar, TAB+_("Print")+PARS(key)+TAB+_("Print image file.")+PARS(key), printicon, this, ID_PRINT, BUTTON_TOOLBAR|FRAME_RAISED);
653 
654     // Separator
655     toolbarSeparator(toolbar);
656 
657     // Note : Ctrl+ and Ctrl- cannot be changed from the registry!
658 
659     // Toolbar button: Zoom in
660     btn = new FXButton(toolbar, TAB+_("Zoom in")+PARS("Ctrl+")+TAB+_("Zoom in image.")+PARS("Ctrl+"), zoominicon, this, ID_ZOOM_IN, ICON_ABOVE_TEXT|BUTTON_TOOLBAR|FRAME_RAISED);
661     hotkey = (CONTROLMASK<<16) |  KEY_KP_Add;
662     btn->addHotKey(hotkey);
663 
664     // Toolbar button: Zoom out
665     btn = new FXButton(toolbar, TAB+_("Zoom out")+PARS("Ctrl-")+TAB+_("Zoom out image.")+PARS("Ctrl-"), zoomouticon, this, ID_ZOOM_OUT, ICON_ABOVE_TEXT|BUTTON_TOOLBAR|FRAME_RAISED);
666     hotkey = (CONTROLMASK<<16) | KEY_KP_Subtract;
667     btn->addHotKey(hotkey);
668 
669     // Toolbar button: Zoom 100%
670     key = getApp()->reg().readStringEntry("KEYBINDINGS", "zoom_100", "Ctrl-I");
671     new FXButton(toolbar, TAB+_("Zoom 100%")+PARS(key)+TAB+_("Zoom image to 100%.")+PARS(key), zoom100icon, this, ID_ZOOM_100, ICON_ABOVE_TEXT|BUTTON_TOOLBAR|FRAME_RAISED);
672 
673     // Toolbar button: Zoom to fit window
674     key = getApp()->reg().readStringEntry("KEYBINDINGS", "zoom_win", "Ctrl-F");
675     new FXButton(toolbar, TAB+_("Zoom to fit")+PARS(key)+TAB+_("Zoom to fit window.")+PARS(key), zoomwinicon, this, ID_ZOOM_WIN, ICON_ABOVE_TEXT|BUTTON_TOOLBAR|FRAME_RAISED);
676 
677     // Separator
678     toolbarSeparator(toolbar);
679 
680     // Toolbar button: Rotate left
681     key = getApp()->reg().readStringEntry("KEYBINDINGS", "rotate_left", "Ctrl-L");
682     new FXButton(toolbar, TAB+_("Rotate left")+PARS(key)+TAB+_("Rotate left image.")+PARS(key), rotatelefticon, this, ID_ROTATE_90, ICON_ABOVE_TEXT|BUTTON_TOOLBAR|FRAME_RAISED);
683 
684     // Toolbar button: Rotate right
685     key = getApp()->reg().readStringEntry("KEYBINDINGS", "rotate_right", "Ctrl-R");
686     new FXButton(toolbar, TAB+_("Rotate right")+PARS(key)+TAB+_("Rotate right image.")+PARS(key), rotaterighticon, this, ID_ROTATE_270, ICON_ABOVE_TEXT|BUTTON_TOOLBAR|FRAME_RAISED);
687 
688     // Toolbar button: mirror horizontally
689     key = getApp()->reg().readStringEntry("KEYBINDINGS", "mirror_horizontally", "Ctrl-Shift-H");
690     new FXButton(toolbar, TAB+_("Mirror horizontally")+PARS(key)+TAB+_("Mirror image horizontally.")+PARS(key), fliplricon, this, ID_MIRROR_HOR, ICON_ABOVE_TEXT|BUTTON_TOOLBAR|FRAME_RAISED);
691 
692     // Toolbar button: mirror vertically
693     key = getApp()->reg().readStringEntry("KEYBINDINGS", "mirror_vertically", "Ctrl-Shift-V");
694     new FXButton(toolbar, TAB+_("Mirror vertically")+PARS(key)+TAB+_("Mirror image vertically.")+PARS(key), flipudicon, this, ID_MIRROR_VER, ICON_ABOVE_TEXT|BUTTON_TOOLBAR|FRAME_RAISED);
695 
696     // File Menu entries
697     FXMenuCommand* mc = NULL;
698     FXString       text;
699 
700     key = getApp()->reg().readStringEntry("KEYBINDINGS", "open", "Ctrl-O");
701     text = _("&Open...")+TABS(key)+_("Open image file.")+PARS(key);
702     mc = new FXMenuCommand(filemenu, text, fileopenicon, this, ID_OPEN);
703     hotkey = _parseAccel(key);
704     getAccelTable()->addAccel(hotkey, mc, FXSEL(SEL_COMMAND, FXMenuCommand::ID_ACCEL));
705 
706     key = getApp()->reg().readStringEntry("KEYBINDINGS", "print", "Ctrl-P");
707     text = _("&Print...")+TABS(key)+_("Print image file.")+PARS(key);
708     mc = new FXMenuCommand(filemenu, text, printicon, this, ID_PRINT);
709     hotkey = _parseAccel(key);
710     getAccelTable()->addAccel(hotkey, mc, FXSEL(SEL_COMMAND, FXMenuCommand::ID_ACCEL));
711 
712     // Recent file menu; this automatically hides if there are no files
713     FXMenuSeparator* sep1 = new FXMenuSeparator(filemenu);
714     sep1->setTarget(&mrufiles);
715     sep1->setSelector(FXRecentFiles::ID_ANYFILES);
716     new FXMenuCommand(filemenu, FXString::null, NULL, &mrufiles, FXRecentFiles::ID_FILE_1);
717     new FXMenuCommand(filemenu, FXString::null, NULL, &mrufiles, FXRecentFiles::ID_FILE_2);
718     new FXMenuCommand(filemenu, FXString::null, NULL, &mrufiles, FXRecentFiles::ID_FILE_3);
719     new FXMenuCommand(filemenu, FXString::null, NULL, &mrufiles, FXRecentFiles::ID_FILE_4);
720     new FXMenuCommand(filemenu, FXString::null, NULL, &mrufiles, FXRecentFiles::ID_FILE_5);
721     new FXMenuCommand(filemenu, _("&Clear recent files")+TAB2+_("Clear recent file menu."), NULL, &mrufiles, FXRecentFiles::ID_CLEAR);
722     FXMenuSeparator* sep2 = new FXMenuSeparator(filemenu);
723     sep2->setTarget(&mrufiles);
724     sep2->setSelector(FXRecentFiles::ID_ANYFILES);
725 
726     key = getApp()->reg().readStringEntry("KEYBINDINGS", "quit", "Ctrl-Q");
727     text = _("&Quit")+TABS(key)+_("Quit Xfi.")+PARS(key);
728     mc = new FXMenuCommand(filemenu, text, quiticon, this, ID_QUIT);
729     hotkey = _parseAccel(key);
730     getAccelTable()->addAccel(hotkey, mc, FXSEL(SEL_COMMAND, FXMenuCommand::ID_ACCEL));
731     getAccelTable()->addAccel(KEY_Escape, this, FXSEL(SEL_COMMAND, ID_QUIT));
732 
733     // Image Menu entries
734     new FXMenuCommand(imagemenu, _("Zoom &in")+TAB+(FXString)"Ctrl+"+TAB+_("Zoom in image.")+PARS("Ctrl+"), zoominicon, this, ID_ZOOM_IN);
735     new FXMenuCommand(imagemenu, _("Zoom &out")+TAB+(FXString)"Ctrl-"+TAB+_("Zoom out image.")+PARS("Ctrl-"), zoomouticon, this, ID_ZOOM_OUT);
736 
737     key = getApp()->reg().readStringEntry("KEYBINDINGS", "zoom_100", "Ctrl-I");
738     text = _("Zoo&m 100%")+TABS(key)+_("Zoom image to 100%.")+PARS(key);
739     mc = new FXMenuCommand(imagemenu, text, zoom100icon, this, ID_ZOOM_100);
740     hotkey = _parseAccel(key);
741     getAccelTable()->addAccel(hotkey, mc, FXSEL(SEL_COMMAND, FXMenuCommand::ID_ACCEL));
742 
743     key = getApp()->reg().readStringEntry("KEYBINDINGS", "zoom_win", "Ctrl-F");
744     text = _("Zoom to fit &window")+TABS(key)+_("Zoom to fit window.")+PARS(key);
745     mc = new FXMenuCommand(imagemenu, text, zoomwinicon, this, ID_ZOOM_WIN);
746     hotkey = _parseAccel(key);
747     getAccelTable()->addAccel(hotkey, mc, FXSEL(SEL_COMMAND, FXMenuCommand::ID_ACCEL));
748 
749     key = getApp()->reg().readStringEntry("KEYBINDINGS", "rotate_right", "Ctrl-R");
750     text = _("Rotate &right")+TABS(key)+_("Rotate right.")+PARS(key);
751     mc = new FXMenuCommand(imagemenu, text, rotaterighticon, this, ID_ROTATE_270);
752     hotkey = _parseAccel(key);
753     getAccelTable()->addAccel(hotkey, mc, FXSEL(SEL_COMMAND, FXMenuCommand::ID_ACCEL));
754 
755     key = getApp()->reg().readStringEntry("KEYBINDINGS", "rotate_left", "Ctrl-L");
756     text = _("Rotate &left")+TABS(key)+_("Rotate left.")+PARS(key);
757     mc = new FXMenuCommand(imagemenu, text, rotatelefticon, this, ID_ROTATE_90);
758     hotkey = _parseAccel(key);
759     getAccelTable()->addAccel(hotkey, mc, FXSEL(SEL_COMMAND, FXMenuCommand::ID_ACCEL));
760 
761     key = getApp()->reg().readStringEntry("KEYBINDINGS", "mirror_horizontally", "Ctrl-Shift-H");
762     text = _("Mirror &horizontally")+TABS(key)+_("Mirror horizontally.")+PARS(key);
763     mc = new FXMenuCommand(imagemenu, text, fliplricon, this, ID_MIRROR_HOR);
764     hotkey = _parseAccel(key);
765     getAccelTable()->addAccel(hotkey, mc, FXSEL(SEL_COMMAND, FXMenuCommand::ID_ACCEL));
766 
767     key = getApp()->reg().readStringEntry("KEYBINDINGS", "mirror_vertically", "Ctrl-Shift-V");
768     text = _("Mirror &vertically")+TABS(key)+_("Mirror vertically.")+PARS(key);
769     mc = new FXMenuCommand(imagemenu, text, flipudicon, this, ID_MIRROR_VER);
770     hotkey = _parseAccel(key);
771     getAccelTable()->addAccel(hotkey, mc, FXSEL(SEL_COMMAND, FXMenuCommand::ID_ACCEL));
772 
773     // View Menu entries
774     key = getApp()->reg().readStringEntry("KEYBINDINGS", "hidden_files", "Ctrl-F6");
775     text = _("&Hidden files")+TABS(key)+_("Show hidden files and folders.")+PARS(key);
776     mc = new FXMenuCheck(viewmenu, text, this, ID_TOGGLE_HIDDEN);
777     hotkey = _parseAccel(key);
778     getAccelTable()->addAccel(hotkey, mc, FXSEL(SEL_COMMAND, FXMenuCommand::ID_ACCEL));
779 
780     key = getApp()->reg().readStringEntry("KEYBINDINGS", "thumbnails", "Ctrl-F7");
781     text = _("&Thumbnails")+TABS(key)+_("Show image thumbnails.")+PARS(key);
782     mc = new FXMenuCheck(viewmenu, text, this, ID_TOGGLE_THUMBNAILS);
783     hotkey = _parseAccel(key);
784     getAccelTable()->addAccel(hotkey, mc, FXSEL(SEL_COMMAND, FXMenuCommand::ID_ACCEL));
785 
786     new FXMenuSeparator(viewmenu);
787 
788     key = getApp()->reg().readStringEntry("KEYBINDINGS", "big_icons", "F10");
789     text = _("&Big icons")+TABS(key)+_("Display folders with big icons.")+PARS(key);
790     mc = new FXMenuRadio(viewmenu, text, this, ID_SHOW_BIG_ICONS);
791     hotkey = _parseAccel(key);
792     getAccelTable()->addAccel(hotkey, mc, FXSEL(SEL_COMMAND, FXMenuCommand::ID_ACCEL));
793 
794     key = getApp()->reg().readStringEntry("KEYBINDINGS", "small_icons", "F11");
795     text = _("&Small icons")+TABS(key)+_("Display folders with small icons.")+PARS(key);
796     mc = new FXMenuRadio(viewmenu, text, this, ID_SHOW_MINI_ICONS);
797     hotkey = _parseAccel(key);
798     getAccelTable()->addAccel(hotkey, mc, FXSEL(SEL_COMMAND, FXMenuCommand::ID_ACCEL));
799 
800     key = getApp()->reg().readStringEntry("KEYBINDINGS", "detailed_file_list", "F12");
801     text = _("&Detailed file list")+TABS(key)+_("Display detailed folder listing.")+PARS(key);
802     mc = new FXMenuRadio(viewmenu, text, this, ID_SHOW_DETAILS);
803     hotkey = _parseAccel(key);
804     getAccelTable()->addAccel(hotkey, mc, FXSEL(SEL_COMMAND, FXMenuCommand::ID_ACCEL));
805 
806     new FXMenuSeparator(viewmenu);
807 
808     mc = new FXMenuRadio(viewmenu, _("&Vertical panels"), this, XFileImage::ID_VERT_PANELS);
809     key = getApp()->reg().readStringEntry("KEYBINDINGS", "vert_panels", "Ctrl-Shift-F1");
810     mc->setAccelText(key);
811 
812     mc = new FXMenuRadio(viewmenu, _("&Horizontal panels"), this, XFileImage::ID_HORZ_PANELS);
813     key = getApp()->reg().readStringEntry("KEYBINDINGS", "horz_panels", "Ctrl-Shift-F2");
814     mc->setAccelText(key);
815 
816     new FXMenuSeparator(viewmenu);
817     new FXMenuRadio(viewmenu, _("&Rows")+TAB2+_("View icons row-wise."), filelist, FileList::ID_ARRANGE_BY_ROWS);
818     new FXMenuRadio(viewmenu, _("&Columns")+TAB2+_("View icons column-wise."), filelist, FileList::ID_ARRANGE_BY_COLUMNS);
819     new FXMenuCheck(viewmenu, _("&Autosize")+TAB2+_("Autosize icon names."), filelist, FileList::ID_AUTOSIZE);
820 
821     // Preferences menu
822     new FXMenuCheck(prefsmenu, _("&Toolbar")+TAB2+_("Display toolbar."), toolbar, FXWindow::ID_TOGGLESHOWN);
823     new FXMenuCheck(prefsmenu, _("&File list")+TAB2+_("Display file list."), filebox, FXWindow::ID_TOGGLESHOWN);
824     new FXMenuCheck(prefsmenu, _("File list &before")+TAB2+_("Display file list before image window."), this, ID_TOGGLE_FILELIST_BEFORE);
825     new FXMenuCheck(prefsmenu, _("&Filter images")+TAB2+_("List only image files."), this, ID_TOGGLE_FILTER_IMAGES);
826     new FXMenuCheck(prefsmenu, _("Fit &window when opening")+TAB2+_("Zoom to fit window when opening an image."), this, ID_TOGGLE_FIT_WIN);
827 
828 
829     // Help Menu entries
830     key = getApp()->reg().readStringEntry("KEYBINDINGS", "help", "F1");
831     text = _("&About X File Image")+TABS(key)+_("About X File Image.")+PARS(key);
832     mc = new FXMenuCommand(helpmenu, text, NULL, this, ID_ABOUT, 0);
833     hotkey = _parseAccel(key);
834     getAccelTable()->addAccel(hotkey, mc, FXSEL(SEL_COMMAND, FXMenuCommand::ID_ACCEL));
835 
836     // Close accelerator
837     key = getApp()->reg().readStringEntry("KEYBINDINGS", "close", "Ctrl-W");
838     hotkey = _parseAccel(key);
839     getAccelTable()->addAccel(hotkey, this, FXSEL(SEL_COMMAND, XFileImage::ID_QUIT));
840 
841     // Make a tool tip
842     new FXToolTip(getApp(), TOOLTIP_NORMAL);
843 
844     // Images
845     img = NULL;
846     tmpimg = NULL;
847 
848     // Dialogs
849     printdialog = NULL;
850 
851     // Recent files
852     mrufiles.setTarget(this);
853     mrufiles.setSelector(ID_RECENTFILE);
854 
855     // Initialize file name
856     filename = "";
857 
858     // Initialize some flags
859     fileview = ID_SHOW_MINI_ICONS;
860     hiddenfiles = false;
861 
862     // Initialize zoom to 100%
863     indZoom = ZOOM_100;
864     zoomval = zoomtab[indZoom];
865     fitwin = false;
866     filterimgs = false;
867 
868     // Initialize previous window width / height
869     prev_width = getWidth();
870     prev_height = getHeight();
871 }
872 
873 
874 // Clean up
~XFileImage()875 XFileImage::~XFileImage()
876 {
877     delete toolbar;
878     delete menubar;
879     delete statusbar;
880     delete filemenu;
881     delete imagemenu;
882     delete helpmenu;
883     delete prefsmenu;
884     delete viewmenu;
885     delete dragshell1;
886     delete pathlink;
887     delete pathtext;
888     delete filelist;
889     delete img;
890     delete tmpimg;
891     delete printdialog;
892     delete btnbackhist;
893     delete btnforwardhist;
894 }
895 
896 
onCmdPopupMenu(FXObject * o,FXSelector s,void * p)897 long XFileImage::onCmdPopupMenu(FXObject* o, FXSelector s, void* p)
898 {
899     // Popup menu pane
900     FXMenuPane menu(this);
901     int        x, y;
902     FXuint     state;
903 
904     getRoot()->getCursorPosition(x, y, state);
905 
906     new FXMenuCommand(&menu, _("Go ho&me"), homeicon, this, ID_GO_HOME);
907     new FXMenuCommand(&menu, _("Go &work"), workicon, this, ID_GO_WORK);
908     new FXMenuSeparator(&menu);
909     new FXMenuCheck(&menu, _("&Hidden files"), this, ID_TOGGLE_HIDDEN);
910     new FXMenuCheck(&menu, _("Thum&bnails"), this, ID_TOGGLE_THUMBNAILS);
911     new FXMenuSeparator(&menu);
912     new FXMenuRadio(&menu, _("B&ig icons"), this, ID_SHOW_BIG_ICONS);
913     new FXMenuRadio(&menu, _("&Small icons"), this, ID_SHOW_MINI_ICONS);
914     new FXMenuRadio(&menu, _("Fu&ll file list"), this, ID_SHOW_DETAILS);
915     new FXMenuSeparator(&menu);
916     new FXMenuRadio(&menu, _("&Rows"), filelist, FileList::ID_ARRANGE_BY_ROWS);
917     new FXMenuRadio(&menu, _("&Columns"), filelist, FileList::ID_ARRANGE_BY_COLUMNS);
918     new FXMenuCheck(&menu, _("Autosize"), filelist, FileList::ID_AUTOSIZE);
919     new FXMenuSeparator(&menu);
920     new FXMenuRadio(&menu, _("&Name"), filelist, FileList::ID_SORT_BY_NAME);
921     new FXMenuRadio(&menu, _("Si&ze"), filelist, FileList::ID_SORT_BY_SIZE);
922     new FXMenuRadio(&menu, _("&Type"), filelist, FileList::ID_SORT_BY_TYPE);
923     new FXMenuRadio(&menu, _("E&xtension"), filelist, FileList::ID_SORT_BY_EXT);
924     new FXMenuRadio(&menu, _("&Date"), filelist, FileList::ID_SORT_BY_TIME);
925     new FXMenuRadio(&menu, _("&User"), filelist, FileList::ID_SORT_BY_USER);
926     new FXMenuRadio(&menu, _("&Group"), filelist, FileList::ID_SORT_BY_GROUP);
927     new FXMenuRadio(&menu, _("&Permissions"), filelist, FileList::ID_SORT_BY_PERM);
928     new FXMenuSeparator(&menu);
929     new FXMenuCheck(&menu, _("Ignore c&ase"), filelist, FileList::ID_SORT_CASE);
930     new FXMenuCheck(&menu, _("Fold&ers first"), filelist, FileList::ID_DIRS_FIRST);
931     new FXMenuCheck(&menu, _("Re&verse order"), filelist, FileList::ID_SORT_REVERSE);
932 
933     menu.create();
934     allowPopupScroll = true;  // Allow keyboard scrolling
935     menu.popup(NULL, x, y);
936     getApp()->runModalWhileShown(&menu);
937     allowPopupScroll = false;
938     return(1);
939 }
940 
941 
942 // If Shift-F10 or Menu is pressed, opens the popup menu
onKeyPress(FXObject * sender,FXSelector sel,void * ptr)943 long XFileImage::onKeyPress(FXObject* sender, FXSelector sel, void* ptr)
944 {
945     FXEvent* event = (FXEvent*)ptr;
946 
947     // Shift-F10 or Menu was pressed : open popup menu
948    	if ((event->state&SHIFTMASK && event->code == KEY_F10) || event->code == KEY_Menu)
949     {
950         this->handle(sender, FXSEL(SEL_COMMAND, XFileImage::ID_POPUP_MENU), ptr);
951         return(1);
952     }
953 
954     // Any other key was pressed : handle the pressed key in the usual way
955     else
956     {
957         if (FXTopWindow::onKeyPress(sender, sel, ptr))
958         {
959             return(1);
960         }
961     }
962 
963     return(0);
964 }
965 
966 
onKeyRelease(FXObject * sender,FXSelector sel,void * ptr)967 long XFileImage::onKeyRelease(FXObject* sender, FXSelector sel, void* ptr)
968 {
969     if (FXTopWindow::onKeyRelease(sender, sel, ptr))
970     {
971         return(1);
972     }
973 
974     return(0);
975 }
976 
977 
978 // User clicked up directory button
onCmdDirUp(FXObject *,FXSelector,void *)979 long XFileImage::onCmdDirUp(FXObject*, FXSelector, void*)
980 {
981     filelist->setDirectory(FXPath::upLevel(filelist->getDirectory()));
982     pathlink->setPath(filelist->getDirectory());
983     pathtext->setText(filelist->getDirectory());
984 
985     filelist->setFocus();
986 
987     return(1);
988 }
989 
990 
991 // Can we still go up
onUpdDirUp(FXObject * sender,FXSelector,void *)992 long XFileImage::onUpdDirUp(FXObject* sender, FXSelector, void*)
993 {
994     if (FXPath::isTopDirectory(filelist->getDirectory()))
995     {
996         sender->handle(this, FXSEL(SEL_COMMAND, ID_DISABLE), NULL);
997     }
998     else
999     {
1000         sender->handle(this, FXSEL(SEL_COMMAND, ID_ENABLE), NULL);
1001     }
1002     return(1);
1003 }
1004 
1005 
1006 // Directory back
onCmdDirBack(FXObject *,FXSelector s,void * p)1007 long XFileImage::onCmdDirBack(FXObject*, FXSelector s, void* p)
1008 {
1009     StringList* backhist, *forwardhist;
1010     StringItem* item;
1011     FXString    pathname;
1012 
1013     // Get the filelist history
1014     backhist = filelist->backhist;
1015     forwardhist = filelist->forwardhist;
1016 
1017     // Get the previous directory
1018     item = backhist->getFirst();
1019     if (item)
1020     {
1021         pathname = backhist->getString(item);
1022     }
1023 
1024     // Update the history
1025     backhist->removeFirstItem();
1026     forwardhist->insertFirstItem(filelist->getDirectory());
1027 
1028     // Go to to the previous directory
1029     filelist->setDirectory(pathname, false);
1030     pathlink->setPath(filelist->getDirectory());
1031     pathtext->setText(filelist->getDirectory());
1032 
1033     filelist->setFocus();
1034 
1035     return(1);
1036 }
1037 
1038 
1039 // Update directory back
onUpdDirBack(FXObject * sender,FXSelector sel,void * ptr)1040 long XFileImage::onUpdDirBack(FXObject* sender, FXSelector sel, void* ptr)
1041 {
1042     StringList* backhist;
1043     FXString    pathname;
1044 
1045     // Get the filelist history
1046     backhist = filelist->backhist;
1047 
1048     // Gray out the button if no item in history
1049     if (backhist->getNumItems() == 0)
1050     {
1051         sender->handle(this, FXSEL(SEL_COMMAND, ID_DISABLE), ptr);
1052     }
1053     else
1054     {
1055         sender->handle(this, FXSEL(SEL_COMMAND, ID_ENABLE), ptr);
1056     }
1057 
1058     return(1);
1059 }
1060 
1061 
1062 // Directory forward
onCmdDirForward(FXObject *,FXSelector s,void * p)1063 long XFileImage::onCmdDirForward(FXObject*, FXSelector s, void* p)
1064 {
1065     StringList* backhist, *forwardhist;
1066     StringItem* item;
1067     FXString    pathname;
1068 
1069     // Get the filelist history
1070     backhist = filelist->backhist;
1071     forwardhist = filelist->forwardhist;
1072 
1073     // Get the next directory
1074     item = forwardhist->getFirst();
1075     if (item)
1076     {
1077         pathname = forwardhist->getString(item);
1078     }
1079 
1080     // Update the history
1081     forwardhist->removeFirstItem();
1082     backhist->insertFirstItem(filelist->getDirectory());
1083 
1084     // Go to to the previous directory
1085     filelist->setDirectory(pathname, false);
1086     pathlink->setPath(filelist->getDirectory());
1087     pathtext->setText(filelist->getDirectory());
1088 
1089     filelist->setFocus();
1090 
1091     return(1);
1092 }
1093 
1094 
1095 // Update directory forward
onUpdDirForward(FXObject * sender,FXSelector sel,void * ptr)1096 long XFileImage::onUpdDirForward(FXObject* sender, FXSelector sel, void* ptr)
1097 {
1098     StringList* forwardhist;
1099     FXString    pathname;
1100 
1101     // Get the filelist history
1102     forwardhist = filelist->forwardhist;
1103 
1104     // Gray out the button if no item in history
1105     if (forwardhist->getNumItems() == 0)
1106     {
1107         sender->handle(this, FXSEL(SEL_COMMAND, ID_DISABLE), ptr);
1108     }
1109     else
1110     {
1111         sender->handle(this, FXSEL(SEL_COMMAND, ID_ENABLE), ptr);
1112     }
1113 
1114     return(1);
1115 }
1116 
1117 
1118 // Directory back history
onCmdDirBackHist(FXObject * sender,FXSelector sel,void * ptr)1119 long XFileImage::onCmdDirBackHist(FXObject* sender, FXSelector sel, void* ptr)
1120 {
1121     StringList* backhist, *forwardhist;
1122     StringItem* item;
1123     FXString    pathname;
1124 
1125     // Get the filelist history
1126     backhist = filelist->backhist;
1127     forwardhist = filelist->forwardhist;
1128 
1129     // Get all string items and display them in a list box
1130     int num = backhist->getNumItems();
1131     if (num > 0)
1132     {
1133         FXString* dirs = new FXString[num];
1134         FXString  strlist = "";
1135 
1136         // Get string items
1137         item = backhist->getFirst();
1138         for (int i = 0; i <= num-1; i++)
1139         {
1140             if (item)
1141             {
1142                 FXString str = backhist->getString(item);
1143                 dirs[i] = str;
1144                 strlist = strlist+str+"\n";
1145                 item = backhist->getNext(item);
1146             }
1147         }
1148 
1149         // Display list box
1150         int pos = DirHistBox::box(btnbackhist, DECOR_NONE, strlist, this->getX()+245, this->getY()+37);
1151 
1152         // If an item was selected
1153         if (pos != -1)
1154         {
1155             // Update back history
1156             if (pos == num-1)
1157             {
1158                 backhist->removeAllItems();
1159             }
1160             else
1161             {
1162                 item = backhist->getItemAtPos(pos+1);
1163                 backhist->removeAllItemsBefore(item);
1164             }
1165 
1166             // Update forward history
1167             forwardhist->insertFirstItem(filelist->getDirectory());
1168             if (pos > 0)
1169             {
1170                 for (int i = 0; i <= pos-1; i++)
1171                 {
1172                     forwardhist->insertFirstItem(dirs[i]);
1173                 }
1174             }
1175 
1176             // Go to to the selected directory
1177             pathname = dirs[pos];
1178             filelist->setDirectory(pathname, false);
1179             pathlink->setPath(filelist->getDirectory());
1180             pathtext->setText(filelist->getDirectory());
1181         }
1182         delete[]dirs;
1183     }
1184 
1185     return(1);
1186 }
1187 
1188 
1189 // Update directory back
onUpdDirBackHist(FXObject * sender,FXSelector sel,void * ptr)1190 long XFileImage::onUpdDirBackHist(FXObject* sender, FXSelector sel, void* ptr)
1191 {
1192     StringList* backhist;
1193     FXString    pathname;
1194 
1195     // Get the filelist history
1196     backhist = filelist->backhist;
1197 
1198     // Gray out the button if no item in history
1199     if (backhist->getNumItems() == 0)
1200     {
1201         sender->handle(this, FXSEL(SEL_COMMAND, ID_DISABLE), ptr);
1202     }
1203     else
1204     {
1205         sender->handle(this, FXSEL(SEL_COMMAND, ID_ENABLE), ptr);
1206     }
1207 
1208     return(1);
1209 }
1210 
1211 
1212 // Directory forward history
onCmdDirForwardHist(FXObject * sender,FXSelector sel,void * ptr)1213 long XFileImage::onCmdDirForwardHist(FXObject* sender, FXSelector sel, void* ptr)
1214 {
1215     StringList* backhist, *forwardhist;
1216     StringItem* item;
1217     FXString    pathname;
1218 
1219     // Get the filelist history
1220     backhist = filelist->backhist;
1221     forwardhist = filelist->forwardhist;
1222 
1223     // Get all string items and display them in a list box
1224     int num = forwardhist->getNumItems();
1225     if (num > 0)
1226     {
1227         FXString* dirs = new FXString[num];
1228         FXString  strlist = "";
1229 
1230         // Get string items
1231         item = forwardhist->getFirst();
1232         for (int i = 0; i <= num-1; i++)
1233         {
1234             if (item)
1235             {
1236                 FXString str = forwardhist->getString(item);
1237                 dirs[i] = str;
1238                 strlist = strlist+str+"\n";
1239                 item = forwardhist->getNext(item);
1240             }
1241         }
1242 
1243         // Display list box
1244         int pos = DirHistBox::box(btnforwardhist, DECOR_NONE, strlist, this->getX()+285, this->getY()+37);
1245 
1246         // If an item was selected
1247         if (pos != -1)
1248         {
1249             // Update forward history
1250             if (pos == num-1)
1251             {
1252                 forwardhist->removeAllItems();
1253             }
1254             else
1255             {
1256                 item = forwardhist->getItemAtPos(pos+1);
1257                 forwardhist->removeAllItemsBefore(item);
1258             }
1259 
1260             // Update back history
1261             backhist->insertFirstItem(filelist->getDirectory());
1262             if (pos > 0)
1263             {
1264                 for (int i = 0; i <= pos-1; i++)
1265                 {
1266                     backhist->insertFirstItem(dirs[i]);
1267                 }
1268             }
1269 
1270             // Go to to the selected directory
1271             pathname = dirs[pos];
1272             filelist->setDirectory(pathname, false);
1273             pathlink->setPath(filelist->getDirectory());
1274             pathtext->setText(filelist->getDirectory());
1275         }
1276         delete[]dirs;
1277     }
1278 
1279     return(1);
1280 }
1281 
1282 
1283 // Update directory forward
onUpdDirForwardHist(FXObject * sender,FXSelector sel,void * ptr)1284 long XFileImage::onUpdDirForwardHist(FXObject* sender, FXSelector sel, void* ptr)
1285 {
1286     StringList* forwardhist;
1287     FXString    pathname;
1288 
1289     // Get the filelist history
1290     forwardhist = filelist->forwardhist;
1291 
1292     // Gray out the button if no item in history
1293     if (forwardhist->getNumItems() == 0)
1294     {
1295         sender->handle(this, FXSEL(SEL_COMMAND, ID_DISABLE), ptr);
1296     }
1297     else
1298     {
1299         sender->handle(this, FXSEL(SEL_COMMAND, ID_ENABLE), ptr);
1300     }
1301 
1302     return(1);
1303 }
1304 
1305 
1306 // Back to home directory
onCmdHome(FXObject *,FXSelector,void *)1307 long XFileImage::onCmdHome(FXObject*, FXSelector, void*)
1308 {
1309     filelist->setDirectory(FXSystem::getHomeDirectory());
1310     pathlink->setPath(filelist->getDirectory());
1311     pathtext->setText(filelist->getDirectory());
1312     filelist->setFocus();
1313     return(1);
1314 }
1315 
1316 
1317 // Back to current working directory
onCmdWork(FXObject *,FXSelector,void *)1318 long XFileImage::onCmdWork(FXObject*, FXSelector, void*)
1319 {
1320     filelist->setDirectory(FXSystem::getCurrentDirectory());
1321     pathlink->setPath(filelist->getDirectory());
1322     pathtext->setText(filelist->getDirectory());
1323     filelist->setFocus();
1324     return(1);
1325 }
1326 
1327 
1328 // About box
onCmdAbout(FXObject *,FXSelector,void *)1329 long XFileImage::onCmdAbout(FXObject*, FXSelector, void*)
1330 {
1331     FXString msg;
1332 
1333     msg.format(_("X File Image Version %s is a simple image viewer.\n\n"), VERSION);
1334     msg += COPYRIGHT;
1335     MessageBox about(this, _("About X File Image"), msg.text(), xfiicon, BOX_OK|DECOR_TITLE|DECOR_BORDER,
1336                      JUSTIFY_CENTER_X|ICON_BEFORE_TEXT|LAYOUT_CENTER_Y|LAYOUT_LEFT|LAYOUT_FILL_X|LAYOUT_FILL_Y);
1337     about.execute(PLACEMENT_OWNER);
1338 
1339     filelist->setFocus();
1340 
1341     return(1);
1342 }
1343 
1344 
1345 // Load file
loadimage(const FXString & file)1346 FXbool XFileImage::loadimage(const FXString& file)
1347 {
1348     FXString ext = FXPath::extension(file);
1349 
1350     FILE* fp = fopen(file.text(), "r");
1351 
1352     if (!fp)
1353     {
1354         MessageBox::error(this, BOX_OK, _("Error Loading File"), _("Unable to open file: %s"), file.text());
1355         return(false);
1356     }
1357     else
1358     {
1359         fclose(fp);
1360     }
1361 
1362     // Free old image if any, before loading a new one
1363     if (img)
1364     {
1365         delete img;
1366         img = NULL;
1367     }
1368     if (tmpimg)
1369     {
1370         delete tmpimg;
1371         tmpimg = NULL;
1372     }
1373 
1374     if (comparecase(ext, "gif") == 0)
1375     {
1376         img = new FXGIFImage(getApp(), NULL, IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP);
1377         tmpimg = new FXGIFImage(getApp(), NULL, IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP);
1378     }
1379     else if (comparecase(ext, "bmp") == 0)
1380     {
1381         img = new FXBMPImage(getApp(), NULL, IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP);
1382         tmpimg = new FXBMPImage(getApp(), NULL, IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP);
1383     }
1384     else if (comparecase(ext, "xpm") == 0)
1385     {
1386         img = new FXXPMImage(getApp(), NULL, IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP);
1387         tmpimg = new FXXPMImage(getApp(), NULL, IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP);
1388     }
1389     else if (comparecase(ext, "pcx") == 0)
1390     {
1391         img = new FXPCXImage(getApp(), NULL, IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP);
1392         tmpimg = new FXPCXImage(getApp(), NULL, IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP);
1393     }
1394     else if ((comparecase(ext, "ico") == 0) || (comparecase(ext, "cur") == 0))
1395     {
1396         img = new FXICOImage(getApp(), NULL, IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP);
1397         tmpimg = new FXICOImage(getApp(), NULL, IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP);
1398     }
1399     else if (comparecase(ext, "tga") == 0)
1400     {
1401         img = new FXTGAImage(getApp(), NULL, IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP);
1402         tmpimg = new FXTGAImage(getApp(), NULL, IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP);
1403     }
1404     else if (comparecase(ext, "rgb") == 0)
1405     {
1406         img = new FXRGBImage(getApp(), NULL, IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP);
1407     }
1408     else if (comparecase(ext, "xbm") == 0)
1409     {
1410         img = new FXXBMImage(getApp(), NULL, NULL, IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP);
1411         tmpimg = new FXXBMImage(getApp(), NULL, NULL, IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP);
1412     }
1413     else if (comparecase(ext, "ppm") == 0)
1414     {
1415         img = new FXPPMImage(getApp(), NULL, IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP);
1416         tmpimg = new FXPPMImage(getApp(), NULL, IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP);
1417     }
1418     else if (comparecase(ext, "png") == 0)
1419     {
1420         img = new FXPNGImage(getApp(), NULL, IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP);
1421         tmpimg = new FXPNGImage(getApp(), NULL, IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP);
1422     }
1423     else if ((comparecase(ext, "jpg") == 0) || (comparecase(ext, "jpeg") == 0))
1424     {
1425         img = new FXJPGImage(getApp(), NULL, IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP);
1426         tmpimg = new FXJPGImage(getApp(), NULL, IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP);
1427     }
1428     else if ((comparecase(ext, "tif") == 0) || (comparecase(ext, "tiff") == 0))
1429     {
1430         img = new FXTIFImage(getApp(), NULL, IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP);
1431         tmpimg = new FXTIFImage(getApp(), NULL, IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP);
1432     }
1433     else
1434     {
1435         img = NULL;
1436         tmpimg = NULL;
1437     }
1438 
1439     // Perhaps failed
1440     if (img == NULL)
1441     {
1442         MessageBox::error(this, BOX_OK, _("Error Loading Image"), _("Unsupported type: %s"), ext.text());
1443         return(false);
1444     }
1445 
1446     if (tmpimg == NULL)
1447     {
1448         MessageBox::error(this, BOX_OK, _("Error Loading Image"), _("Unsupported type: %s"), ext.text());
1449         return(false);
1450     }
1451 
1452     // Load it
1453     FXFileStream stream;
1454     if (stream.open(file, FXStreamLoad))
1455     {
1456         getApp()->beginWaitCursor();
1457         FXbool res = img->loadPixels(stream);
1458 
1459         stream.close();
1460 
1461         // If failed
1462         if (!res)
1463         {
1464             MessageBox::error(this, BOX_OK, _("Error Loading Image"), _("Unable to load image, the file may be corrupted"));
1465             getApp()->endWaitCursor();
1466             return(false);
1467         }
1468 
1469         if (!FXMEMDUP(&tmpdata, img->getData(), FXColor, img->getWidth()*img->getHeight()))
1470         {
1471             throw FXMemoryException(_("Unable to load image"));
1472         }
1473         tmpimg->setData(tmpdata, IMAGE_OWNED, img->getWidth(), img->getHeight());
1474 
1475         img->create();
1476         tmpimg->create();
1477 
1478         imageview->setImage(tmpimg);
1479 
1480         // Initial zoom and image format
1481         indZoom = ZOOM_100;
1482         zoomval = zoomtab[indZoom];
1483         getApp()->endWaitCursor();
1484 
1485         // Zoom to fit window if asked
1486         if (fitwin)
1487         {
1488             handle(this, FXSEL(SEL_COMMAND, ID_ZOOM_WIN), NULL);
1489         }
1490     }
1491     filelist->setDirectory(FXPath::directory(file));
1492     pathlink->setPath(filelist->getDirectory());
1493     pathtext->setText(filelist->getDirectory());
1494 
1495     return(true);
1496 }
1497 
1498 
1499 // Toggle file list before image
onCmdToggleFileListBefore(FXObject * sender,FXSelector,void *)1500 long XFileImage::onCmdToggleFileListBefore(FXObject* sender, FXSelector, void*)
1501 {
1502     filelistbefore = !filelistbefore;
1503 
1504     if (BOX_CLICKED_CANCEL != MessageBox::question(this, BOX_OK_CANCEL, _("Restart"), _("Change will be taken into account after restart.\nRestart X File Image now?")))
1505     {
1506         this->handle(this, FXSEL(SEL_COMMAND, XFileImage::ID_RESTART), NULL);
1507     }
1508 
1509     return(1);
1510 }
1511 
1512 
1513 // Update file list before image
onUpdToggleFileListBefore(FXObject * sender,FXSelector,void *)1514 long XFileImage::onUpdToggleFileListBefore(FXObject* sender, FXSelector, void*)
1515 {
1516     if (filebox->shown())
1517     {
1518         sender->handle(this, FXSEL(SEL_COMMAND, ID_ENABLE), NULL);
1519         if (filelistbefore)
1520         {
1521             sender->handle(this, FXSEL(SEL_COMMAND, ID_CHECK), NULL);
1522         }
1523         else
1524         {
1525             sender->handle(this, FXSEL(SEL_COMMAND, ID_UNCHECK), NULL);
1526         }
1527     }
1528     else
1529     {
1530         sender->handle(this, FXSEL(SEL_COMMAND, ID_DISABLE), NULL);
1531     }
1532 
1533     return(1);
1534 }
1535 
1536 
1537 // Toggle zoom to fit window on startup
onCmdToggleFitWin(FXObject *,FXSelector,void *)1538 long XFileImage::onCmdToggleFitWin(FXObject*, FXSelector, void*)
1539 {
1540     fitwin = !fitwin;
1541     filelist->setFocus();
1542     return(1);
1543 }
1544 
1545 
1546 // Update toggle wrap mode
onUpdToggleFitWin(FXObject * sender,FXSelector,void *)1547 long XFileImage::onUpdToggleFitWin(FXObject* sender, FXSelector, void*)
1548 {
1549     if (fitwin)
1550     {
1551         sender->handle(this, FXSEL(SEL_COMMAND, ID_CHECK), NULL);
1552     }
1553     else
1554     {
1555         sender->handle(this, FXSEL(SEL_COMMAND, ID_UNCHECK), NULL);
1556     }
1557     return(1);
1558 }
1559 
1560 
1561 // Toggle filter image files
onCmdToggleFilterImages(FXObject *,FXSelector,void *)1562 long XFileImage::onCmdToggleFilterImages(FXObject*, FXSelector, void*)
1563 {
1564     filterimgs = !filterimgs;
1565     if (filterimgs)
1566     {
1567         filelist->setPattern(imgpatterns);
1568     }
1569     else
1570     {
1571         filelist->setPattern("*");
1572     }
1573 
1574     filelist->setFocus();
1575 
1576     return(1);
1577 }
1578 
1579 
1580 // Update filter image files
onUpdToggleFilterImages(FXObject * sender,FXSelector,void *)1581 long XFileImage::onUpdToggleFilterImages(FXObject* sender, FXSelector, void*)
1582 {
1583     // Disable menu item if the file list is not shown
1584     if (filebox->shown())
1585     {
1586         sender->handle(this, FXSEL(SEL_COMMAND, FXWindow::ID_ENABLE), NULL);
1587 
1588         // Update menu item
1589         if (filterimgs)
1590         {
1591             sender->handle(this, FXSEL(SEL_COMMAND, ID_CHECK), NULL);
1592         }
1593         else
1594         {
1595             sender->handle(this, FXSEL(SEL_COMMAND, ID_UNCHECK), NULL);
1596         }
1597     }
1598     else
1599     {
1600         sender->handle(this, FXSEL(SEL_COMMAND, FXWindow::ID_DISABLE), NULL);
1601 
1602         // Update menu item
1603         if (filterimgs)
1604         {
1605             sender->handle(this, FXSEL(SEL_COMMAND, ID_CHECK), NULL);
1606         }
1607         else
1608         {
1609             sender->handle(this, FXSEL(SEL_COMMAND, ID_UNCHECK), NULL);
1610         }
1611     }
1612     return(1);
1613 }
1614 
1615 
1616 // Open
onCmdOpen(FXObject *,FXSelector,void *)1617 long XFileImage::onCmdOpen(FXObject*, FXSelector, void*)
1618 {
1619     FileDialog opendialog(this, _("Open Image"));
1620 
1621     opendialog.setSelectMode(SELECTFILE_EXISTING);
1622     opendialog.setPatternList(patterns);
1623     opendialog.setDirectory(filelist->getDirectory());
1624     if (opendialog.execute())
1625     {
1626         filename = opendialog.getFilename();
1627         filelist->setCurrentFile(filename);
1628         mrufiles.appendFile(filename);
1629         loadimage(filename);
1630     }
1631 
1632     return(1);
1633 }
1634 
1635 
1636 // Print the text
onCmdPrint(FXObject *,FXSelector,void *)1637 long XFileImage::onCmdPrint(FXObject*, FXSelector, void*)
1638 {
1639     // Read the current print command from the registry
1640     FXString printcommand, command;
1641 
1642     printcommand = getApp()->reg().readStringEntry("OPTIONS", "print_command", "lpr -P printer");
1643 
1644     // Open print dialog filled with the current print command
1645     int rc = 1;
1646     if (printdialog == NULL)
1647     {
1648         printdialog = new InputDialog(this, printcommand, _("Print command: \n(ex: lpr -P <printer>)"), _("Print"), "", printbigicon);
1649     }
1650     printdialog->setText(printcommand);
1651     printdialog->CursorEnd();
1652     rc = printdialog->execute(PLACEMENT_CURSOR);
1653     printcommand = printdialog->getText();
1654 
1655     // If cancel was pressed, exit
1656     if (!rc)
1657     {
1658         return(0);
1659     }
1660 
1661     // Write the new print command to the registry
1662     getApp()->reg().writeStringEntry("OPTIONS", "print_command", printcommand.text());
1663 
1664     // Perform the print command
1665     command = "cat " + filename + " |" + printcommand + " &";
1666     int ret = system(command.text());
1667     if (ret < 0)
1668     {
1669         MessageBox::error(this, BOX_OK, _("Error"), _("Can't execute command %s"), command.text());
1670         return(0);
1671     }
1672 
1673     return(1);
1674 }
1675 
1676 
1677 // Handle toggle hidden command
onCmdToggleHidden(FXObject * sender,FXSelector sel,void * ptr)1678 long XFileImage::onCmdToggleHidden(FXObject* sender, FXSelector sel, void* ptr)
1679 {
1680     filelist->handle(sender, FXSEL(SEL_COMMAND, FileList::ID_TOGGLE_HIDDEN), ptr);
1681     filelist->setFocus();
1682 
1683     return(1);
1684 }
1685 
1686 
1687 // Update toggle hidden command
onUpdToggleHidden(FXObject * sender,FXSelector sel,void * ptr)1688 long XFileImage::onUpdToggleHidden(FXObject* sender, FXSelector sel, void* ptr)
1689 {
1690     FXuint msg = FXWindow::ID_UNCHECK;
1691 
1692     hiddenfiles = filelist->shownHiddenFiles();
1693 
1694     if (hiddenfiles == true)
1695     {
1696         msg = FXWindow::ID_CHECK;
1697     }
1698     sender->handle(this, FXSEL(SEL_COMMAND, msg), ptr);
1699 
1700     // Disable menu item if the file list is not shown
1701     if (filebox->shown())
1702     {
1703         sender->handle(this, FXSEL(SEL_COMMAND, FXWindow::ID_ENABLE), NULL);
1704     }
1705     else
1706     {
1707         sender->handle(this, FXSEL(SEL_COMMAND, FXWindow::ID_DISABLE), NULL);
1708     }
1709 
1710     return(1);
1711 }
1712 
1713 
1714 // Handle toggle hidden command
onCmdToggleThumbnails(FXObject * sender,FXSelector sel,void * ptr)1715 long XFileImage::onCmdToggleThumbnails(FXObject* sender, FXSelector sel, void* ptr)
1716 {
1717     filelist->handle(sender, FXSEL(SEL_COMMAND, FileList::ID_TOGGLE_THUMBNAILS), ptr);
1718     filelist->setFocus();
1719 
1720     return(1);
1721 }
1722 
1723 
1724 // Update toggle hidden command
onUpdToggleThumbnails(FXObject * sender,FXSelector sel,void * ptr)1725 long XFileImage::onUpdToggleThumbnails(FXObject* sender, FXSelector sel, void* ptr)
1726 {
1727     FXuint msg = FXWindow::ID_UNCHECK;
1728 
1729     thumbnails = filelist->shownThumbnails();
1730 
1731     if (thumbnails == true)
1732     {
1733         msg = FXWindow::ID_CHECK;
1734     }
1735     sender->handle(this, FXSEL(SEL_COMMAND, msg), ptr);
1736 
1737     // Disable menu item if the file list is not shown
1738     if (filebox->shown())
1739     {
1740         sender->handle(this, FXSEL(SEL_COMMAND, FXWindow::ID_ENABLE), NULL);
1741     }
1742     else
1743     {
1744         sender->handle(this, FXSEL(SEL_COMMAND, FXWindow::ID_DISABLE), NULL);
1745     }
1746 
1747     return(1);
1748 }
1749 
1750 
1751 // Show mini icons in file list
onCmdShowMini(FXObject *,FXSelector,void *)1752 long XFileImage::onCmdShowMini(FXObject*, FXSelector, void*)
1753 {
1754     fileview = ID_SHOW_MINI_ICONS;
1755     filelist->handle(this, FXSEL(SEL_COMMAND, FileList::ID_SHOW_MINI_ICONS), NULL);
1756     filelist->setFocus();
1757 
1758     return(1);
1759 }
1760 
1761 
1762 // Show big icons in file list
onCmdShowBig(FXObject *,FXSelector,void *)1763 long XFileImage::onCmdShowBig(FXObject*, FXSelector, void*)
1764 {
1765     fileview = ID_SHOW_BIG_ICONS;
1766     filelist->handle(this, FXSEL(SEL_COMMAND, FileList::ID_SHOW_BIG_ICONS), NULL);
1767     filelist->setFocus();
1768 
1769     return(1);
1770 }
1771 
1772 
1773 // Show details in file list
onCmdShowDetails(FXObject *,FXSelector,void *)1774 long XFileImage::onCmdShowDetails(FXObject*, FXSelector, void*)
1775 {
1776     fileview = ID_SHOW_DETAILS;
1777     filelist->handle(this, FXSEL(SEL_COMMAND, FileList::ID_SHOW_DETAILS), NULL);
1778     filelist->setFocus();
1779 
1780     return(1);
1781 }
1782 
1783 
1784 // Update filelist
onUpdFileView(FXObject * sender,FXSelector sel,void * ptr)1785 long XFileImage::onUpdFileView(FXObject* sender, FXSelector sel, void* ptr)
1786 {
1787     // Keep the filebox width / height relative to the window width / height
1788 
1789     // Get the current width and height
1790     int width = getWidth();
1791     int height = getHeight();
1792 
1793     // Panel stacked horizontally
1794     if (vertpanels)
1795     {
1796         if (relative_resize && (prev_width != width))
1797         {
1798             // File box shown
1799             if (filebox->shown())
1800             {
1801                 filebox->setWidth((int)round(filewidth_pct*width));
1802             }
1803         }
1804 
1805         // Update the relative width (only if window width is sufficient)
1806         prev_width = width;
1807         if (getWidth() > 10)
1808         {
1809             filewidth_pct = (double)(filebox->getWidth())/(double)(getWidth());
1810         }
1811     }
1812 
1813     // Panel stacked vertically
1814     else
1815     {
1816         if (relative_resize && (prev_height != height))
1817         {
1818             // File box shown
1819             if (filebox->shown())
1820             {
1821                 filebox->setHeight((int)round(fileheight_pct*height));
1822             }
1823         }
1824 
1825         // Update the relative height (only if window height is sufficient)
1826         prev_height = height;
1827         if (getHeight() > 10)
1828         {
1829             fileheight_pct = (double)(filebox->getHeight())/(double)(getHeight());
1830         }
1831     }
1832 
1833     // Update radio buttons
1834     FXuint msg = FXWindow::ID_UNCHECK;
1835 
1836     switch (FXSELID(sel))
1837     {
1838     case ID_SHOW_MINI_ICONS:
1839         if (fileview == ID_SHOW_MINI_ICONS)
1840         {
1841             msg = FXWindow::ID_CHECK;
1842         }
1843         break;
1844 
1845     case ID_SHOW_BIG_ICONS:
1846         if (fileview == ID_SHOW_BIG_ICONS)
1847         {
1848             msg = FXWindow::ID_CHECK;
1849         }
1850         break;
1851 
1852     case ID_SHOW_DETAILS:
1853         if (fileview == ID_SHOW_DETAILS)
1854         {
1855             msg = FXWindow::ID_CHECK;
1856         }
1857         break;
1858     }
1859     sender->handle(this, FXSEL(SEL_COMMAND, msg), NULL);
1860 
1861     // Disable menus items if the file list is not shown
1862     if (filebox->shown())
1863     {
1864         sender->handle(this, FXSEL(SEL_COMMAND, FXWindow::ID_ENABLE), NULL);
1865     }
1866     else
1867     {
1868         sender->handle(this, FXSEL(SEL_COMMAND, FXWindow::ID_DISABLE), NULL);
1869     }
1870 
1871     return(1);
1872 }
1873 
1874 
1875 // Harvest the zombies
onSigHarvest(FXObject *,FXSelector,void *)1876 long XFileImage::onSigHarvest(FXObject*, FXSelector, void*)
1877 {
1878     while (waitpid(-1, NULL, WNOHANG) > 0)
1879     {
1880     }
1881     return(1);
1882 }
1883 
1884 
1885 // Quit
onCmdQuit(FXObject *,FXSelector,void *)1886 long XFileImage::onCmdQuit(FXObject*, FXSelector, void*)
1887 {
1888     // Save settings
1889     saveConfig();
1890 
1891     // Quit
1892     getApp()->exit(EXIT_SUCCESS);
1893     return(1);
1894 }
1895 
1896 
1897 // Update title (display image size and actual zoom)
onUpdTitle(FXObject * sender,FXSelector,void *)1898 long XFileImage::onUpdTitle(FXObject* sender, FXSelector, void*)
1899 {
1900     FXString title = "Xfi " + filename;
1901     FXImage* image = imageview->getImage();
1902 
1903     if (image && (img != NULL))
1904     {
1905         title += " (" + FXStringVal(img->getWidth()) + "x" + FXStringVal(img->getHeight()) + " - " + FXStringVal(zoomval*100) + "%" ")";
1906     }
1907     sender->handle(this, FXSEL(SEL_COMMAND, FXWindow::ID_SETSTRINGVALUE), (void*)&title);
1908     return(1);
1909 }
1910 
1911 
1912 // Open recent file
onCmdRecentFile(FXObject *,FXSelector,void * ptr)1913 long XFileImage::onCmdRecentFile(FXObject*, FXSelector, void* ptr)
1914 {
1915     filename = (char*)ptr;
1916     filelist->setCurrentFile(filename);
1917     loadimage(filename);
1918     return(1);
1919 }
1920 
1921 
1922 // Double clicked in the file list
onCmdItemDoubleClicked(FXObject *,FXSelector,void * ptr)1923 long XFileImage::onCmdItemDoubleClicked(FXObject*, FXSelector, void* ptr)
1924 {
1925     int index = (int)(FXival)ptr;
1926 
1927     if (0 <= index)
1928     {
1929         if (filelist->isItemDirectory(index))
1930         {
1931             FXString pathname = filelist->getItemPathname(index);
1932 
1933             // Does not have access
1934             if (!::isReadExecutable(pathname))
1935             {
1936                 MessageBox::error(this, BOX_OK, _("Error"), _(" Permission to: %s denied."), pathname.text());
1937                 return(0);
1938             }
1939             filelist->setDirectory(pathname);
1940             pathlink->setPath(pathname);
1941             pathtext->setText(pathname);
1942         }
1943         else if (filelist->isItemFile(index))
1944         {
1945             filename = filelist->getItemPathname(index);
1946             mrufiles.appendFile(filename);
1947             loadimage(filename);
1948             filelist->setCurrentItem(index);
1949         }
1950     }
1951     return(1);
1952 }
1953 
1954 
1955 // Single clicked in the file list
onCmdItemClicked(FXObject * sender,FXSelector sel,void * ptr)1956 long XFileImage::onCmdItemClicked(FXObject* sender, FXSelector sel, void* ptr)
1957 {
1958     if (single_click != SINGLE_CLICK_NONE)
1959     {
1960         // In detailed mode, avoid single click when cursor is not over the first column
1961         int    x, y;
1962         FXuint state;
1963         filelist->getCursorPosition(x, y, state);
1964         FXbool allow = true;
1965         if (!(filelist->getListStyle()&(_ICONLIST_BIG_ICONS|_ICONLIST_MINI_ICONS)) && ((x-filelist->getXPosition()) > filelist->getHeaderSize(0)))
1966         {
1967             allow = false;
1968         }
1969 
1970         int index = (int)(FXival)ptr;
1971         if (0 <= index)
1972         {
1973             if ((single_click != SINGLE_CLICK_NONE) && filelist->isItemDirectory(index) && allow)
1974             {
1975                 FXString pathname = filelist->getItemPathname(index);
1976 
1977                 // Does not have access
1978                 if (!::isReadExecutable(pathname))
1979                 {
1980                     MessageBox::error(this, BOX_OK, _("Error"), _(" Permission to: %s denied."), pathname.text());
1981                     return(0);
1982                 }
1983                 filelist->setDirectory(pathname);
1984                 pathlink->setPath(pathname);
1985                 pathtext->setText(pathname);
1986             }
1987             else if ((single_click == SINGLE_CLICK_DIR_FILE) && filelist->isItemFile(index) && allow)
1988             {
1989                 filename = filelist->getItemPathname(index);
1990                 mrufiles.appendFile(filename);
1991                 loadimage(filename);
1992                 filelist->setCurrentItem(index);
1993             }
1994         }
1995     }
1996     return(1);
1997 }
1998 
1999 
2000 // Rotate image
onCmdRotate(FXObject *,FXSelector sel,void *)2001 long XFileImage::onCmdRotate(FXObject*, FXSelector sel, void*)
2002 {
2003     getApp()->beginWaitCursor();
2004     FXImage* image = imageview->getImage();
2005     switch (FXSELID(sel))
2006     {
2007     case ID_ROTATE_90:
2008 
2009         // Rotate the actual image
2010         image->rotate(90);
2011 
2012         // Need to also rotate the original image only if the actual size is different
2013         if ((image->getWidth() != img->getWidth()) || (image->getHeight() != img->getHeight()))
2014         {
2015             img->rotate(90);
2016         }
2017         break;
2018 
2019     case ID_ROTATE_270:
2020 
2021         // Rotate the actual image
2022         image->rotate(270);
2023 
2024         // Need to also rotate the original image only if the actual size is different
2025         if ((image->getWidth() != img->getWidth()) || (image->getHeight() != img->getHeight()))
2026         {
2027             img->rotate(270);
2028         }
2029         break;
2030     }
2031     imageview->setImage(image);
2032     filelist->setFocus();
2033     getApp()->endWaitCursor();
2034     return(1);
2035 }
2036 
2037 
2038 // Update image
onUpdImage(FXObject * sender,FXSelector,void *)2039 long XFileImage::onUpdImage(FXObject* sender, FXSelector, void*)
2040 {
2041     if (imageview->getImage())
2042     {
2043         sender->handle(this, FXSEL(SEL_COMMAND, FXWindow::ID_ENABLE), NULL);
2044     }
2045     else
2046     {
2047         sender->handle(this, FXSEL(SEL_COMMAND, FXWindow::ID_DISABLE), NULL);
2048     }
2049     return(1);
2050 }
2051 
2052 
2053 // Mirror image
onCmdMirror(FXObject *,FXSelector sel,void *)2054 long XFileImage::onCmdMirror(FXObject*, FXSelector sel, void*)
2055 {
2056     getApp()->beginWaitCursor();
2057     FXImage* image = imageview->getImage();
2058     switch (FXSELID(sel))
2059     {
2060     case ID_MIRROR_HOR:
2061 
2062         // Mirror the actual image
2063         image->mirror(true, false);
2064 
2065         // Need to also mirror the original image only if the actual size is different
2066         if ((image->getWidth() != img->getWidth()) || (image->getHeight() != img->getHeight()))
2067         {
2068             img->mirror(true, false);
2069         }
2070         break;
2071 
2072     case ID_MIRROR_VER:
2073 
2074         // Mirror the actual image
2075         image->mirror(false, true);
2076 
2077         // Need to also mirror the original image only if the actual size is different
2078         if ((image->getWidth() != img->getWidth()) || (image->getHeight() != img->getHeight()))
2079         {
2080             img->mirror(false, true);
2081         }
2082         break;
2083     }
2084     imageview->setImage(image);
2085     filelist->setFocus();
2086     getApp()->endWaitCursor();
2087     return(1);
2088 }
2089 
2090 
2091 // Zoom in image
onCmdZoomIn(FXObject *,FXSelector,void *)2092 long XFileImage::onCmdZoomIn(FXObject*, FXSelector, void*)
2093 {
2094     getApp()->beginWaitCursor();
2095 
2096     // Copy the original image into the actual one
2097     if (!FXMEMDUP(&tmpdata, img->getData(), FXColor, img->getWidth()*img->getHeight()))
2098     {
2099         throw FXMemoryException(_("Unable to load image"));
2100     }
2101     tmpimg->setData(tmpdata, IMAGE_OWNED, img->getWidth(), img->getHeight());
2102 
2103     // Resize the actual image according to the new zoom factor
2104     indZoom += 1;
2105     if (indZoom > NB_ZOOM-1)
2106     {
2107         indZoom = NB_ZOOM-1;
2108     }
2109     int sx = (int)(tmpimg->getWidth()*zoomtab[indZoom]);
2110     int sy = (int)(tmpimg->getHeight()*zoomtab[indZoom]);
2111 
2112     // Scale only if the actual image size is different
2113     if (indZoom == ZOOM_100)
2114     {
2115         imageview->setImage(img);
2116     }
2117     else
2118     {
2119         // Maximum zoom allowed
2120         if ((sx > MAX_IMGSIZE) || (sy > MAX_IMGSIZE))
2121         {
2122             indZoom -= 1;
2123             if (indZoom < 0)
2124             {
2125                 indZoom = 0;
2126             }
2127             sx = (int)(tmpimg->getWidth()*zoomtab[indZoom]);
2128             sy = (int)(tmpimg->getHeight()*zoomtab[indZoom]);
2129         }
2130 
2131         // Scale image according to the new zoom factor
2132         tmpimg->scale(sx, sy, 1);
2133         imageview->setImage(tmpimg);
2134     }
2135 
2136     // Set zoom value for window title
2137     zoomval = zoomtab[indZoom];
2138 
2139     filelist->setFocus();
2140     getApp()->endWaitCursor();
2141     return(1);
2142 }
2143 
2144 
2145 // Zoom out image
onCmdZoomOut(FXObject *,FXSelector,void *)2146 long XFileImage::onCmdZoomOut(FXObject*, FXSelector, void*)
2147 {
2148     getApp()->beginWaitCursor();
2149 
2150     // Copy the original image into the actual one
2151     if (!FXMEMDUP(&tmpdata, img->getData(), FXColor, img->getWidth()*img->getHeight()))
2152     {
2153         throw FXMemoryException(_("Unable to load image"));
2154     }
2155     tmpimg->setData(tmpdata, IMAGE_OWNED, img->getWidth(), img->getHeight());
2156 
2157     // Resize the image according to the new zoom factor
2158     indZoom -= 1;
2159     if (indZoom < 0)
2160     {
2161         indZoom = 0;
2162     }
2163     int sx = (int)(tmpimg->getWidth()*zoomtab[indZoom]);
2164     int sy = (int)(tmpimg->getHeight()*zoomtab[indZoom]);
2165 
2166     // Scale only if the actual image size is different
2167     if (indZoom == ZOOM_100)
2168     {
2169         imageview->setImage(img);
2170     }
2171     else
2172     {
2173         // Scale image according to the new zoom factor
2174         tmpimg->scale(sx, sy, 1);
2175         imageview->setImage(tmpimg);
2176     }
2177 
2178     // Set zoom value for window title
2179     zoomval = zoomtab[indZoom];
2180 
2181     filelist->setFocus();
2182     getApp()->endWaitCursor();
2183     return(1);
2184 }
2185 
2186 
2187 // Zoom to 100%
onCmdZoom100(FXObject *,FXSelector,void *)2188 long XFileImage::onCmdZoom100(FXObject*, FXSelector, void*)
2189 {
2190     getApp()->beginWaitCursor();
2191     indZoom = ZOOM_100;
2192     zoomval = zoomtab[indZoom];
2193     imageview->setImage(img);
2194     filelist->setFocus();
2195     getApp()->endWaitCursor();
2196     return(1);
2197 }
2198 
2199 
2200 // Zoom to fit window
onCmdZoomWin(FXObject *,FXSelector,void *)2201 long XFileImage::onCmdZoomWin(FXObject*, FXSelector, void*)
2202 {
2203     getApp()->beginWaitCursor();
2204 
2205     // Window and image sizes
2206     int winw = imageview->getWidth();
2207     int winh = imageview->getHeight();
2208     int w = img->getWidth();
2209     int h = img->getHeight();
2210 
2211     // Compute zoom factor
2212     double fitwin;
2213     if (double(w)/double(h) > double(winw)/double(winh))
2214     {
2215         fitwin = 0.98*(double)winw/(double)w;
2216     }
2217     else
2218     {
2219         fitwin = 0.98*(double)winh/(double)h;
2220     }
2221 
2222     // Find the most approaching predefined zoom
2223     // This is used in other zoom functions
2224     for (int k = 0; k < NB_ZOOM; k++)
2225     {
2226         if (zoomtab[k] > fitwin)
2227         {
2228             indZoom = k-1;
2229             break;
2230         }
2231     }
2232     if (indZoom < 0)
2233     {
2234         indZoom = 0;
2235     }
2236     if (indZoom >= NB_ZOOM)
2237     {
2238         indZoom = NB_ZOOM-1;
2239     }
2240 
2241     // Copy the original image into the actual one
2242     if (!FXMEMDUP(&tmpdata, img->getData(), FXColor, img->getWidth()*img->getHeight()))
2243     {
2244         throw FXMemoryException(_("Unable to load image"));
2245     }
2246     tmpimg->setData(tmpdata, IMAGE_OWNED, img->getWidth(), img->getHeight());
2247 
2248     // Resize the image according to the new zoom factor
2249     int sx = (int)(w*fitwin);
2250     int sy = (int)(h*fitwin);
2251 
2252     // Scale image according to the new zoom factor
2253     tmpimg->scale(sx, sy, 1);
2254     imageview->setImage(tmpimg);
2255 
2256     // Set zoom value for window title
2257     zoomval = fitwin;
2258 
2259     filelist->setFocus();
2260     getApp()->endWaitCursor();
2261     return(1);
2262 }
2263 
2264 
2265 // Restart the application when required
onCmdRestart(FXObject *,FXSelector,void *)2266 long XFileImage::onCmdRestart(FXObject*, FXSelector, void*)
2267 {
2268     saveConfig();
2269 
2270     if (fork() == 0) // Child
2271     {
2272         execvp("xfi", args);
2273     }
2274     else // Parent
2275     {
2276         exit(EXIT_SUCCESS);
2277     }
2278     return(1);
2279 }
2280 
2281 
2282 // Start the ball rolling
start(FXString startimage)2283 void XFileImage::start(FXString startimage)
2284 {
2285     filename = startimage;
2286     if (filename != "")
2287     {
2288         loadimage(filename);
2289     }
2290 }
2291 
2292 
2293 // Create and show window
create()2294 void XFileImage::create()
2295 {
2296     // Get size and position
2297     FXuint ww = getApp()->reg().readUnsignedEntry("OPTIONS", "width", DEFAULT_WINDOW_WIDTH);    // Workaround for a possible bug in some WMs
2298     FXuint hh = getApp()->reg().readUnsignedEntry("OPTIONS", "height", DEFAULT_WINDOW_HEIGHT);  // Workaround for a possible bug in some WMs
2299 
2300     filewidth_pct = getApp()->reg().readRealEntry("OPTIONS", "filewidth_pct", 0.25);
2301     fileheight_pct = getApp()->reg().readRealEntry("OPTIONS", "fileheight_pct", 0.25);
2302     FXuint fs = getApp()->reg().readIntEntry("OPTIONS", "filesshown", true);
2303 
2304     filelist->setDirectory(FXSystem::getCurrentDirectory());
2305     pathlink->setPath(FXSystem::getCurrentDirectory());
2306     pathtext->setText(FXSystem::getCurrentDirectory());
2307 
2308     // Display or hide path linker and path text
2309     if (show_pathlink)
2310     {
2311         pathtext->hide();
2312         pathlink->show();
2313     }
2314     else
2315     {
2316         pathlink->hide();
2317         pathtext->show();
2318     }
2319 
2320     // Hide tree if asked for
2321     if (!fs)
2322     {
2323         filebox->hide();
2324     }
2325 
2326     // Set toolbar status
2327     if (getApp()->reg().readUnsignedEntry("OPTIONS", "showtoolbar", true) == false)
2328     {
2329         toolbar->hide();
2330     }
2331 
2332     // Set status bar status
2333     if (getApp()->reg().readUnsignedEntry("OPTIONS", "showstatusbar", true) == false)
2334     {
2335         statusbar->hide();
2336     }
2337 
2338     // Set hidden file status
2339     hiddenfiles = getApp()->reg().readUnsignedEntry("OPTIONS", "hiddenfiles", 0);
2340     filelist->showHiddenFiles(hiddenfiles);
2341 
2342     // Set thumbnails status
2343     thumbnails = getApp()->reg().readUnsignedEntry("OPTIONS", "thumbnails", 0);
2344     filelist->showThumbnails(thumbnails);
2345 
2346     // Set list style
2347     liststyle = getApp()->reg().readUnsignedEntry("OPTIONS", "liststyle", _ICONLIST_MINI_ICONS);
2348     filelist->setListStyle(liststyle|_ICONLIST_BROWSESELECT);
2349 
2350     // Set file view
2351     fileview = getApp()->reg().readUnsignedEntry("OPTIONS", "fileview", ID_SHOW_MINI_ICONS);
2352     this->handle(this, FXSEL(SEL_COMMAND, fileview), NULL);
2353 
2354     // Set startup zoom
2355     fitwin = getApp()->reg().readUnsignedEntry("OPTIONS", "fitwin", 0);
2356 
2357     // Set filter images flag
2358     filterimgs = getApp()->reg().readUnsignedEntry("OPTIONS", "filterimgs", false);
2359 
2360     // Set position and position window
2361     if (save_win_pos)
2362     {
2363         int xpos = getApp()->reg().readIntEntry("OPTIONS", "xpos", DEFAULT_WINDOW_XPOS);
2364         int ypos = getApp()->reg().readIntEntry("OPTIONS", "ypos", DEFAULT_WINDOW_YPOS);
2365         position(xpos, ypos, ww, hh);
2366     }
2367     else
2368     {
2369         position(getX(), getY(), ww, hh);
2370     }
2371 
2372     FXMainWindow::create();
2373 
2374     if (filterimgs)
2375     {
2376         filelist->setPattern(imgpatterns);
2377     }
2378 
2379     // Set filebox width or height
2380     if (vertpanels)
2381     {
2382         filebox->setWidth((int)round(filewidth_pct*getWidth()));
2383     }
2384     else
2385     {
2386         filebox->setHeight((int)round(fileheight_pct*getHeight()));
2387     }
2388 
2389     // Set focus on file list
2390     filelist->setFocus();
2391 
2392     show();
2393 
2394 
2395 #ifdef STARTUP_NOTIFICATION
2396     startup_completed();
2397 #endif
2398 }
2399 
2400 
2401 // Switch between vertical and horizontal panels
onCmdHorzVertPanels(FXObject * sender,FXSelector sel,void * ptr)2402 long XFileImage::onCmdHorzVertPanels(FXObject* sender, FXSelector sel, void* ptr)
2403 {
2404     switch (FXSELID(sel))
2405     {
2406     case ID_VERT_PANELS:
2407         splitter->setSplitterStyle(splitter->getSplitterStyle()&~SPLITTER_VERTICAL);
2408         vertpanels = true;
2409         break;
2410 
2411     case ID_HORZ_PANELS:
2412         splitter->setSplitterStyle(splitter->getSplitterStyle()|SPLITTER_VERTICAL);
2413         vertpanels = false;
2414         break;
2415     }
2416 
2417     filelist->setFocus();
2418 
2419     return(1);
2420 }
2421 
2422 
2423 // Update the horizontal / vertical panel radio menus
onUpdHorzVertPanels(FXObject * sender,FXSelector sel,void * ptr)2424 long XFileImage::onUpdHorzVertPanels(FXObject* sender, FXSelector sel, void* ptr)
2425 {
2426     sender->handle(this, FXSEL(SEL_COMMAND, FXWindow::ID_ENABLE), ptr);
2427 
2428     if (vertpanels)
2429     {
2430         if (FXSELID(sel) == ID_HORZ_PANELS)
2431         {
2432             sender->handle(this, FXSEL(SEL_COMMAND, FXWindow::ID_UNCHECK), ptr);
2433         }
2434         else
2435         {
2436             sender->handle(this, FXSEL(SEL_COMMAND, FXWindow::ID_CHECK), ptr);
2437         }
2438     }
2439     else
2440     {
2441         if (FXSELID(sel) == ID_VERT_PANELS)
2442         {
2443             sender->handle(this, FXSEL(SEL_COMMAND, FXWindow::ID_UNCHECK), ptr);
2444         }
2445         else
2446         {
2447             sender->handle(this, FXSEL(SEL_COMMAND, FXWindow::ID_CHECK), ptr);
2448         }
2449     }
2450 
2451     return(1);
2452 }
2453 
2454 
2455 // Save configuration when quitting
saveConfig()2456 void XFileImage::saveConfig()
2457 {
2458     // Write new window size and position back to registry
2459     getApp()->reg().writeUnsignedEntry("OPTIONS", "width", (FXuint)getWidth());
2460     getApp()->reg().writeUnsignedEntry("OPTIONS", "height", (FXuint)getHeight());
2461 
2462     if (save_win_pos)
2463     {
2464         // Account for the Window Manager border size
2465         XWindowAttributes xwattr;
2466         if (XGetWindowAttributes((Display*)getApp()->getDisplay(), this->id(), &xwattr))
2467         {
2468             getApp()->reg().writeIntEntry("OPTIONS", "xpos", getX()-xwattr.x);
2469             getApp()->reg().writeIntEntry("OPTIONS", "ypos", getY()-xwattr.y);
2470         }
2471         else
2472         {
2473             getApp()->reg().writeIntEntry("OPTIONS", "xpos", getX());
2474             getApp()->reg().writeIntEntry("OPTIONS", "ypos", getY());
2475         }
2476     }
2477 
2478     // Width and height of filebox
2479     getApp()->reg().writeRealEntry("OPTIONS", "filewidth_pct", (int)(filewidth_pct*100)/100.0);
2480     getApp()->reg().writeRealEntry("OPTIONS", "fileheight_pct", (int)(fileheight_pct*100)/100.0);
2481 
2482     // Was filebox shown
2483     getApp()->reg().writeIntEntry("OPTIONS", "filesshown", filebox->shown());
2484 
2485     // Toolbar status
2486     if (toolbar->shown())
2487     {
2488         getApp()->reg().writeUnsignedEntry("OPTIONS", "showtoolbar", true);
2489     }
2490     else
2491     {
2492         getApp()->reg().writeUnsignedEntry("OPTIONS", "showtoolbar", false);
2493     }
2494 
2495     // Hidden files status
2496     getApp()->reg().writeUnsignedEntry("OPTIONS", "hiddenfiles", hiddenfiles);
2497 
2498     // Thumbnails status
2499     getApp()->reg().writeUnsignedEntry("OPTIONS", "thumbnails", thumbnails);
2500 
2501     // File view
2502     getApp()->reg().writeUnsignedEntry("OPTIONS", "fileview", fileview);
2503 
2504     // List style
2505     getApp()->reg().writeUnsignedEntry("OPTIONS", "liststyle", filelist->getListStyle());
2506 
2507     // Startup zoom
2508     getApp()->reg().writeUnsignedEntry("OPTIONS", "fitwin", fitwin);
2509 
2510     // Filter images in file list
2511     getApp()->reg().writeUnsignedEntry("OPTIONS", "filterimgs", filterimgs);
2512 
2513     // Filelist columns sizes
2514     getApp()->reg().writeUnsignedEntry("OPTIONS", "name_size", filelist->getHeaderSize(0));
2515     getApp()->reg().writeUnsignedEntry("OPTIONS", "size_size", filelist->getHeaderSize(1));
2516     getApp()->reg().writeUnsignedEntry("OPTIONS", "type_size", filelist->getHeaderSize(2));
2517     getApp()->reg().writeUnsignedEntry("OPTIONS", "ext_size", filelist->getHeaderSize(3));
2518     getApp()->reg().writeUnsignedEntry("OPTIONS", "modd_size", filelist->getHeaderSize(4));
2519     getApp()->reg().writeUnsignedEntry("OPTIONS", "user_size", filelist->getHeaderSize(5));
2520     getApp()->reg().writeUnsignedEntry("OPTIONS", "grou_size", filelist->getHeaderSize(6));
2521     getApp()->reg().writeUnsignedEntry("OPTIONS", "attr_size", filelist->getHeaderSize(7));
2522 
2523     // Panel stacking
2524     getApp()->reg().writeUnsignedEntry("OPTIONS", "filelist_before", filelistbefore);
2525     getApp()->reg().writeUnsignedEntry("OPTIONS", "vert_panels", vertpanels);
2526 
2527     // Get and write sort function for search window
2528     FXString sort_func;
2529     if (filelist->getSortFunc() == filelist->ascendingCase)
2530     {
2531         sort_func = "ascendingCase";
2532     }
2533     if (filelist->getSortFunc() == filelist->ascendingCaseMix)
2534     {
2535         sort_func = "ascendingCaseMix";
2536     }
2537     else if (filelist->getSortFunc() == filelist->descendingCase)
2538     {
2539         sort_func = "descendingCase";
2540     }
2541     else if (filelist->getSortFunc() == filelist->descendingCaseMix)
2542     {
2543         sort_func = "descendingCaseMix";
2544     }
2545     else if (filelist->getSortFunc() == filelist->ascending)
2546     {
2547         sort_func = "ascending";
2548     }
2549     else if (filelist->getSortFunc() == filelist->ascendingMix)
2550     {
2551         sort_func = "ascendingMix";
2552     }
2553     else if (filelist->getSortFunc() == filelist->descending)
2554     {
2555         sort_func = "descending";
2556     }
2557     else if (filelist->getSortFunc() == filelist->descendingMix)
2558     {
2559         sort_func = "descendingMix";
2560     }
2561     else if (filelist->getSortFunc() == filelist->ascendingSize)
2562     {
2563         sort_func = "ascendingSize";
2564     }
2565     else if (filelist->getSortFunc() == filelist->ascendingSizeMix)
2566     {
2567         sort_func = "ascendingSizeMix";
2568     }
2569     else if (filelist->getSortFunc() == filelist->descendingSize)
2570     {
2571         sort_func = "descendingSize";
2572     }
2573     else if (filelist->getSortFunc() == filelist->descendingSizeMix)
2574     {
2575         sort_func = "descendingSizeMix";
2576     }
2577     else if (filelist->getSortFunc() == filelist->ascendingType)
2578     {
2579         sort_func = "ascendingType";
2580     }
2581     else if (filelist->getSortFunc() == filelist->ascendingTypeMix)
2582     {
2583         sort_func = "ascendingTypeMix";
2584     }
2585     else if (filelist->getSortFunc() == filelist->descendingType)
2586     {
2587         sort_func = "descendingType";
2588     }
2589     else if (filelist->getSortFunc() == filelist->descendingTypeMix)
2590     {
2591         sort_func = "descendingTypeMix";
2592     }
2593     else if (filelist->getSortFunc() == filelist->ascendingExt)
2594     {
2595         sort_func = "ascendingExt";
2596     }
2597     else if (filelist->getSortFunc() == filelist->ascendingExtMix)
2598     {
2599         sort_func = "ascendingExtMix";
2600     }
2601     else if (filelist->getSortFunc() == filelist->descendingExt)
2602     {
2603         sort_func = "descendingExt";
2604     }
2605     else if (filelist->getSortFunc() == filelist->descendingExtMix)
2606     {
2607         sort_func = "descendingExtMix";
2608     }
2609     else if (filelist->getSortFunc() == filelist->ascendingTime)
2610     {
2611         sort_func = "ascendingTime";
2612     }
2613     else if (filelist->getSortFunc() == filelist->ascendingTimeMix)
2614     {
2615         sort_func = "ascendingTimeMix";
2616     }
2617     else if (filelist->getSortFunc() == filelist->descendingTime)
2618     {
2619         sort_func = "descendingTime";
2620     }
2621     else if (filelist->getSortFunc() == filelist->descendingTimeMix)
2622     {
2623         sort_func = "descendingTimeMix";
2624     }
2625     else if (filelist->getSortFunc() == filelist->ascendingUser)
2626     {
2627         sort_func = "ascendingUser";
2628     }
2629     else if (filelist->getSortFunc() == filelist->ascendingUserMix)
2630     {
2631         sort_func = "ascendingUserMix";
2632     }
2633     else if (filelist->getSortFunc() == filelist->descendingUser)
2634     {
2635         sort_func = "descendingUser";
2636     }
2637     else if (filelist->getSortFunc() == filelist->descendingUserMix)
2638     {
2639         sort_func = "descendingUserMix";
2640     }
2641     else if (filelist->getSortFunc() == filelist->ascendingGroup)
2642     {
2643         sort_func = "ascendingGroup";
2644     }
2645     else if (filelist->getSortFunc() == filelist->ascendingGroupMix)
2646     {
2647         sort_func = "ascendingGroupMix";
2648     }
2649     else if (filelist->getSortFunc() == filelist->descendingGroup)
2650     {
2651         sort_func = "descendingGroup";
2652     }
2653     else if (filelist->getSortFunc() == filelist->descendingGroupMix)
2654     {
2655         sort_func = "descendingGroupMix";
2656     }
2657     else if (filelist->getSortFunc() == filelist->ascendingPerm)
2658     {
2659         sort_func = "ascendingPerm";
2660     }
2661     else if (filelist->getSortFunc() == filelist->ascendingPermMix)
2662     {
2663         sort_func = "ascendingPermMix";
2664     }
2665     else if (filelist->getSortFunc() == filelist->descendingPerm)
2666     {
2667         sort_func = "descendingPerm";
2668     }
2669     else if (filelist->getSortFunc() == filelist->descendingPermMix)
2670     {
2671         sort_func = "descendingPermMix";
2672     }
2673     else
2674     {
2675         sort_func = "ascendingCase";
2676     }
2677     getApp()->reg().writeStringEntry("OPTIONS", "sort_func", sort_func.text());
2678 
2679     // Write registry settings
2680     getApp()->reg().write();
2681 }
2682 
2683 
2684 // Usage message
2685 #define USAGE_MSG    _("\
2686 \nUsage: xfi [options] [image] \n\
2687 \n\
2688     [options] can be any of the following:\n\
2689 \n\
2690         -h, --help         Print (this) help screen and exit.\n\
2691         -v, --version      Print version information and exit.\n\
2692 \n\
2693     [image] is the path to the image file you want to open on start up.\n\
2694 \n")
2695 
2696 
2697 
2698 // Start the whole thing
main(int argc,char * argv[])2699 int main(int argc, char* argv[])
2700 {
2701     int         i;
2702     FXString    startimage = "";
2703     const char* appname = "xfi";
2704     const char* xfename = XFEAPPNAME;
2705     const char* vdrname = XFEVDRNAME;
2706     FXbool      loadicons;
2707     FXString    xmodifiers;
2708 
2709     // Get environment variables $HOME, $XDG_DATA_HOME and $XDG_CONFIG_HOME
2710     homedir = FXSystem::getHomeDirectory();
2711     if (homedir == "")
2712     {
2713         homedir = ROOTDIR;
2714     }
2715     xdgdatahome = getenv("XDG_DATA_HOME");
2716     if (xdgdatahome == "")
2717     {
2718         xdgdatahome = homedir + PATHSEPSTRING DATAPATH;
2719     }
2720     xdgconfighome = getenv("XDG_CONFIG_HOME");
2721     if (xdgconfighome == "")
2722     {
2723         xdgconfighome = homedir + PATHSEPSTRING CONFIGPATH;
2724     }
2725 
2726     // Detect if an X input method is used
2727     xmodifiers = getenv("XMODIFIERS");
2728     if ((xmodifiers == "") || (xmodifiers == "@im=none"))
2729     {
2730         xim_used = false;
2731     }
2732     else
2733     {
2734         xim_used = true;
2735     }
2736 
2737 #ifdef HAVE_SETLOCALE
2738     // Set locale via LC_ALL.
2739     setlocale(LC_ALL, "");
2740 #endif
2741 
2742 #if ENABLE_NLS
2743     // Set the text message domain.
2744     bindtextdomain(PACKAGE, LOCALEDIR);
2745     bind_textdomain_codeset(PACKAGE, "utf-8");
2746     textdomain(PACKAGE);
2747 #endif
2748 
2749     // Parse basic arguments
2750     for (i = 1; i < argc; ++i)
2751     {
2752         if ((compare(argv[i], "-v") == 0) || (compare(argv[i], "--version") == 0))
2753         {
2754             fprintf(stdout, "%s version %s\n", PACKAGE, VERSION);
2755             exit(EXIT_SUCCESS);
2756         }
2757         else if ((compare(argv[i], "-h") == 0) || (compare(argv[i], "--help") == 0))
2758         {
2759             fprintf(stdout, USAGE_MSG);
2760             exit(EXIT_SUCCESS);
2761         }
2762         else
2763         {
2764             // Start image, if any
2765             startimage = argv[i];
2766         }
2767     }
2768 
2769     args = argv;
2770 
2771     // Make application
2772     FXApp* application = new FXApp(appname, vdrname);
2773 
2774     // Open display
2775     application->init(argc, argv);
2776 
2777     // Read the Xfe registry
2778     FXRegistry* reg_xfe = new FXRegistry(xfename, vdrname);
2779     reg_xfe->read();
2780 
2781 	// Compute integer and fractional scaling factors depending on the monitor resolution
2782 	FXint res = reg_xfe->readUnsignedEntry("SETTINGS", "screenres", 100);
2783 	scaleint = round(res / 100.0);
2784 	scalefrac = FXMAX(1.0, res / 100.0);
2785 
2786     // Redefine the default hand cursor depending on the integer scaling factor
2787     FXCursor* hand;
2788     if (scaleint == 1)
2789     {
2790 		hand = new FXCursor(application, hand1_bits, hand1_mask_bits, hand1_width, hand1_height, hand1_x_hot, hand1_y_hot);
2791 	}
2792 	else if (scaleint == 2)
2793     {
2794 		hand = new FXCursor(application, hand2_bits, hand2_mask_bits, hand2_width, hand2_height, hand2_x_hot, hand2_y_hot);
2795 	}
2796 	else
2797 	{
2798 		hand = new FXCursor(application, hand3_bits, hand3_mask_bits, hand3_width, hand3_height, hand3_x_hot, hand3_y_hot);
2799 	}
2800     application->setDefaultCursor(DEF_HAND_CURSOR, hand);
2801 
2802     // Load all application icons
2803     FXbool iconpathfound = true;
2804     loadicons = loadAppIcons(application, &iconpathfound);
2805 
2806     // Set base color (to change the default base color at first run)
2807     FXColor basecolor = reg_xfe->readColorEntry("SETTINGS", "basecolor", FXRGB(237, 233, 227));
2808     application->setBaseColor(basecolor);
2809 
2810     // Set Xfi normal font according to the Xfe registry
2811     FXString fontspec;
2812     fontspec = reg_xfe->readStringEntry("SETTINGS", "font", DEFAULT_NORMAL_FONT);
2813     if (!fontspec.empty())
2814     {
2815         FXFont* normalFont = new FXFont(application, fontspec);
2816         normalFont->create();
2817         application->setNormalFont(normalFont);
2818     }
2819 
2820     // Set Xfi file list colors according to the Xfe registry
2821     listbackcolor = reg_xfe->readColorEntry("SETTINGS", "listbackcolor", FXRGB(255, 255, 255));
2822     listforecolor = reg_xfe->readColorEntry("SETTINGS", "listforecolor", FXRGB(0, 0, 0));
2823     highlightcolor = reg_xfe->readColorEntry("SETTINGS", "highlightcolor", FXRGB(238, 238, 238));
2824 
2825     // Set single click navigation according to the Xfe registry
2826     single_click = reg_xfe->readUnsignedEntry("SETTINGS", "single_click", SINGLE_CLICK_NONE);
2827 
2828     // Set smooth scrolling according to the Xfe registry
2829     FXbool smoothscroll = reg_xfe->readUnsignedEntry("SETTINGS", "smooth_scroll", true);
2830 
2831     // Set file list tooltip flag according to the Xfe registry
2832     file_tooltips = reg_xfe->readUnsignedEntry("SETTINGS", "file_tooltips", true);
2833 
2834     // Set relative resizing flag according to the Xfe registry
2835     relative_resize = reg_xfe->readUnsignedEntry("SETTINGS", "relative_resize", true);
2836 
2837     // Set display pathlinker flag according to the Xfe registry
2838     show_pathlink = reg_xfe->readUnsignedEntry("SETTINGS", "show_pathlinker", true);
2839 
2840     // Get value of the window position flag
2841     save_win_pos = reg_xfe->readUnsignedEntry("SETTINGS", "save_win_pos", false);
2842 
2843     // Delete the Xfe registry
2844     delete reg_xfe;
2845 
2846     // Make window
2847     XFileImage* window = new XFileImage(application, smoothscroll);
2848 
2849     // Catch SIGCHLD to harvest zombie child processes
2850     application->addSignal(SIGCHLD, window, XFileImage::ID_HARVEST, true);
2851 
2852     // Handle interrupt to save stuff nicely
2853     application->addSignal(SIGINT, window, XFileImage::ID_QUIT);
2854 
2855     // Create it
2856     application->create();
2857 
2858     // Smooth scrolling
2859     window->setSmoothScroll(smoothscroll);
2860 
2861     // Icon path not found
2862     if (!iconpathfound)
2863     {
2864         MessageBox::error(application, BOX_OK, _("Error loading icons"), _("Icon path doesn't exist, icon theme was set back to default. Please check your icon path!") );
2865     }
2866 
2867     // Some icons not found
2868     if (!loadicons)
2869     {
2870         MessageBox::error(application, BOX_OK, _("Error loading icons"), _("Unable to load some icons. Please check your icon theme!"));
2871     }
2872 
2873     // Tooltips setup time and duration
2874     application->setTooltipPause(TOOLTIP_PAUSE);
2875     application->setTooltipTime(TOOLTIP_TIME);
2876 
2877     // Start
2878     window->start(startimage);
2879 
2880     // Run
2881     return(application->run());
2882 }
2883