1 /*
2 ** 1998-05-17 - I just have to build an Opus-look-alike GTK GUI! :)
3 ** 1998-09-11 - Er, it like, grew, or something.
4 */
5
6 #include "gentoo.h"
7
8 #include <dlfcn.h>
9 #include <signal.h>
10 #include <stdlib.h>
11 #include <time.h>
12 #include <sys/wait.h>
13
14 #if defined ENABLE_NLS
15 #include <locale.h>
16 #endif
17
18 #include "errors.h"
19 #include "configure.h"
20 #include "dirpane.h"
21 #include "dialog.h"
22 #include "userinfo.h"
23 #include "file.h"
24 #include "fileutil.h"
25 #include "gfam.h"
26 #include "guiutil.h"
27 #include "xmlutil.h"
28 #include "strutil.h"
29 #include "types.h"
30 #include "styles.h"
31 #include "sizeutil.h"
32 #include "buttons.h"
33 #include "buttonlayout.h"
34 #include "queue.h"
35 #include "cmdseq.h"
36 #include "children.h"
37 #include "dpformat.h"
38 #include "keyboard.h"
39 #include "controls.h"
40 #include "iconutil.h"
41 #include "cmdseq_config.h"
42 #include "menus.h"
43 #include "nag_dialog.h"
44
45 #include "cfg_module.h"
46 #include "cfg_nag.h"
47 #include "cfg_windows.h"
48
49 /* ----------------------------------------------------------------------------------------- */
50
51 /* 1998-05-18 - Filter out files the user really doesn't want to see, and that recursive
52 ** directory traversing code really, really, REALLY, doesn't.
53 */
dir_filter(const gchar * name)54 static gboolean dir_filter(const gchar *name)
55 {
56 if((strcmp(name, ".") == 0) || (strcmp(name, "..") == 0))
57 return FALSE;
58 return TRUE;
59 }
60
61 /* ----------------------------------------------------------------------------------------- */
62
63 /* 2000-03-18 - User clicked close button on window. Just react as if the Quit command was run. */
evt_main_delete(GtkWidget * wid,GdkEventAny * evt,gpointer user)64 static gboolean evt_main_delete(GtkWidget *wid, GdkEventAny *evt, gpointer user)
65 {
66 csq_execute(user, "Quit");
67
68 return TRUE;
69 }
70
71 /* 1998-10-26 - Initialize some fields in the dp structure. */
init_pane(DirPane * dp,gint index)72 static void init_pane(DirPane *dp, gint index)
73 {
74 dp->index = index;
75 dp->complete.prefix[0] = '\0';
76 dp->dir.stat = NULL;
77 dp->dir.stat_alloc = 0;
78 dp->dir.stat_use = 0;
79 dp->hist = dph_dirhistory_new();
80 dp->dir.path[0] = '\0';
81 }
82
evt_paned_notify_position(GObject * obj,GParamSpec * spec,gpointer user)83 static void evt_paned_notify_position(GObject *obj, GParamSpec *spec, gpointer user)
84 {
85 MainInfo *min = user;
86 GdkWindow *pwin;
87 gint pos, np;
88
89 if(!dp_realized(min))
90 return;
91
92 pos = gtk_paned_get_position(GTK_PANED(obj));
93 pwin = gtk_widget_get_window(min->gui->panes);
94 np = min->cfg.dp_paning.orientation == DPORIENT_HORIZ ? gdk_window_get_width(pwin) : gdk_window_get_height(pwin);
95 switch(min->cfg.dp_paning.mode)
96 {
97 case DPSPLIT_FREE:
98 break;
99 case DPSPLIT_RATIO:
100 min->cfg.dp_paning.value = (gdouble) pos / np;
101 break;
102 case DPSPLIT_ABS_LEFT:
103 min->cfg.dp_paning.value = pos;
104 break;
105 case DPSPLIT_ABS_RIGHT:
106 min->cfg.dp_paning.value = np - pos;
107 break;
108 }
109 }
110
111 /* 1998-05-17 - Build a couple of dir-panes.
112 ** 1998-05-18 - Now also puts the panes in a horizontally paned window, for extra Opusity. ;^)
113 ** 1998-08-02 - Fixed *huge* bug where pane 1 (the right) was built using pane 0's format!!
114 */
build_dirpanes(MainInfo * min)115 static GtkWidget * build_dirpanes(MainInfo *min)
116 {
117 GtkWidget *pane;
118 GuiInfo *gui;
119
120 gui = min->gui;
121
122 gui->panes = gtk_paned_new(min->cfg.dp_paning.orientation == DPORIENT_HORIZ ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL);
123 init_pane(&gui->pane[0], 0);
124 pane = dp_build(min, &min->cfg.dp_format[0], &gui->pane[0]);
125 gtk_paned_add1(GTK_PANED(gui->panes), pane);
126 init_pane(&gui->pane[1], 1);
127 pane = dp_build(min, &min->cfg.dp_format[1], &gui->pane[1]);
128 gtk_paned_add2(GTK_PANED(gui->panes), pane);
129 gui->sig_pane_notify = g_signal_connect(G_OBJECT(gui->panes), "notify::position", G_CALLBACK(evt_paned_notify_position), min);
130 gtk_widget_show(gui->panes);
131
132 gtk_widget_grab_focus(min->gui->pane[0].view);
133
134 return gui->panes;
135 }
136
evt_top_button_press_event(GtkWidget * top,GdkEventButton * evt,gpointer user)137 static void evt_top_button_press_event(GtkWidget *top, GdkEventButton *evt, gpointer user)
138 {
139 if(evt->button == 1 && evt->type == GDK_2BUTTON_PRESS)
140 csq_execute(user, "About");
141 }
142
143 /* 1998-05-19 - Create the top widgetry, returning something the caller can just add to a box. Sets the
144 ** <label> pointer to a GtkLabel which can be used later to display funny messages and stuff.
145 ** The label is internally wrapped in a GtkEventbox, which makes updating it possible without
146 ** causing instant epilepsy in everyone watching. GTK+ really is smooth.
147 ** 1998-11-26 - Made the label focusable (?), in order to *finally* have somewhere safe to put the focus
148 ** when I don't want it on path entry widgets. Nice.
149 ** 2010-10-03 - Added sneaky click-listener, so that we can run About on double-click.
150 */
build_top(MainInfo * min)151 static GtkWidget * build_top(MainInfo *min)
152 {
153 GtkLabel **label = (GtkLabel **) &min->gui->top;
154 GtkWidget *top, *lab;
155
156 if(min->cfg.errors.display == ERR_DISPLAY_TITLEBAR)
157 {
158 if(*label != NULL)
159 gtk_widget_destroy(GTK_WIDGET(*label));
160 *label = NULL;
161 return NULL;
162 }
163
164 top = gtk_event_box_new();
165 lab = gtk_label_new("");
166 gtk_container_add(GTK_CONTAINER(top), lab);
167 gtk_widget_show_all(top);
168 if(label != NULL)
169 *label = GTK_LABEL(lab);
170 g_signal_connect(G_OBJECT(top), "button_press_event", G_CALLBACK(evt_top_button_press_event), min);
171
172 return top;
173 }
174
175 /* 2002-05-31 - Rewritten yet again, now using the first weak version of a specialized button layout module. */
build_bottom(MainInfo * min)176 static GtkWidget * build_bottom(MainInfo *min)
177 {
178 GtkWidget *hbox, *sb, *cb;
179
180 if((sb = btn_buttonsheet_build(min, &min->cfg.buttons, "Shortcuts", FALSE, NULL, NULL)) != NULL)
181 btn_buttonsheet_built_add_keys(min, GTK_CONTAINER(sb), NULL);
182 if((cb = btn_buttonsheet_build(min, &min->cfg.buttons, NULL, FALSE, NULL, min)) != NULL)
183 btn_buttonsheet_built_add_keys(min, GTK_CONTAINER(cb), NULL);
184 if((hbox = btl_buttonlayout_pack(min->cfg.buttonlayout, cb, sb)) != NULL)
185 gtk_widget_show_all(hbox);
186
187 return hbox;
188 }
189
rebuild_top(MainInfo * min)190 void rebuild_top(MainInfo *min)
191 {
192 GtkWidget *top;
193
194 if(min->gui->top != NULL)
195 {
196 gtk_widget_destroy(min->gui->top);
197 min->gui->top = NULL;
198 }
199 top = build_top(min);
200 if(top != NULL)
201 {
202 gtk_box_pack_start(GTK_BOX(min->gui->vbox), top, FALSE, FALSE, 0);
203 gtk_box_reorder_child(GTK_BOX(min->gui->vbox), top, 0);
204 }
205 dp_show_stats(min->gui->cur_pane);
206 gui_set_main_title(min, NULL);
207 }
208
209 /* 1998-10-26 - Rebuild the middle part of the GUI, i.e. the panes. */
rebuild_middle(MainInfo * min)210 void rebuild_middle(MainInfo *min)
211 {
212 GtkWidget *left, *right;
213
214 gtk_container_remove(GTK_CONTAINER(min->gui->panes), min->gui->pane[0].vbox);
215 gtk_container_remove(GTK_CONTAINER(min->gui->panes), min->gui->pane[1].vbox);
216 gtk_widget_destroy(min->gui->panes);
217 min->gui->panes = gtk_paned_new(min->cfg.dp_paning.orientation == DPORIENT_HORIZ ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL);
218 gtk_box_pack_start(GTK_BOX(min->gui->vbox), min->gui->panes, TRUE, TRUE, 0);
219 gtk_box_reorder_child(GTK_BOX(min->gui->vbox), min->gui->panes, 1);
220 if((left = dp_build(min, &min->cfg.dp_format[0], &min->gui->pane[0])) != NULL)
221 gtk_paned_add1(GTK_PANED(min->gui->panes), left);
222 if((right = dp_build(min, &min->cfg.dp_format[1], &min->gui->pane[1])) != NULL)
223 gtk_paned_add2(GTK_PANED(min->gui->panes), right);
224 min->gui->sig_pane_notify = g_signal_connect(G_OBJECT(min->gui->panes), "notify::position", G_CALLBACK(evt_paned_notify_position), min);
225 gtk_widget_show(min->gui->panes);
226 dp_split_refresh(min);
227 }
228
229 /* 1998-07-14 - Rebuild the bottom part of the GUI, whose main responsibility is to contain
230 ** the button bank(s).
231 */
rebuild_bottom(MainInfo * min)232 void rebuild_bottom(MainInfo *min)
233 {
234 gtk_widget_destroy(min->gui->bottom);
235 if((min->gui->bottom = build_bottom(min)) != NULL)
236 {
237 gtk_box_pack_start(GTK_BOX(min->gui->vbox), min->gui->bottom, FALSE, FALSE, 0);
238 gtk_widget_show(min->gui->bottom);
239 }
240 }
241
242 /* 2008-04-20 - Replaced old size_allocation-tracking code with new, using configure events instead. */
evt_main_configure(GtkWidget * wid,GdkEventConfigure * req,gpointer user)243 static gboolean evt_main_configure(GtkWidget *wid, GdkEventConfigure *req, gpointer user)
244 {
245 dp_split_refresh(user);
246
247 return FALSE; /* Keep propagating. */
248 }
249
build_gui(MainInfo * min)250 static GtkWidget * build_gui(MainInfo *min)
251 {
252 GtkWidget *top, *panes, *bottom;
253
254 min->gui = g_malloc(sizeof *min->gui);
255 min->gui->window = NULL;
256 min->gui->window = win_window_open(min->cfg.wininfo, WIN_MAIN);
257 gtk_widget_set_name(min->gui->window, "gentoo");
258 g_object_set_data(G_OBJECT(min->gui->window), "user", min);
259 min->gui->sig_main_configure = g_signal_connect(G_OBJECT(min->gui->window), "configure_event", G_CALLBACK(evt_main_configure), min);
260 min->gui->sig_main_delete = g_signal_connect(G_OBJECT(min->gui->window), "delete_event", G_CALLBACK(evt_main_delete), min);
261 min->gui->pane[0].main = min->gui->pane[1].main = min;
262 min->gui->vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
263 min->gui->kbd_ctx = kbd_context_new(min);
264
265 top = build_top(min);
266 if((panes = build_dirpanes(min)) != NULL)
267 {
268 bottom = build_bottom(min);
269 if(top != NULL)
270 gtk_box_pack_start(GTK_BOX(min->gui->vbox), top, FALSE, FALSE, 0);
271 gtk_box_pack_start(GTK_BOX(min->gui->vbox), panes, TRUE, TRUE, 0);
272 if(bottom != NULL)
273 gtk_box_pack_start(GTK_BOX(min->gui->vbox), bottom, FALSE, FALSE, 0);
274 gtk_widget_show_all(min->gui->vbox);
275 min->gui->middle = panes;
276 min->gui->bottom = bottom;
277 min->gui->cur_pane = &min->gui->pane[0];
278 kbd_context_attach(min->gui->kbd_ctx, GTK_WINDOW(min->gui->window));
279 ctrl_keys_install(min->cfg.ctrlinfo, min->gui->kbd_ctx);
280 return min->gui->vbox;
281 }
282 gtk_widget_destroy(top);
283 gtk_widget_destroy(min->gui->vbox);
284
285 return NULL;
286 }
287
288 /* 1998-08-23 - Initialize the paths config data. */
init_paths(CfgInfo * cfg)289 static void init_paths(CfgInfo *cfg)
290 {
291 const gchar *confdir;
292
293 cfg->path.path[PTID_ICON] = g_string_new(PATH_ICN);
294 if((confdir = g_get_user_config_dir()) != NULL)
295 {
296 cfg->path.path[PTID_GTKRC] = g_string_new(confdir);
297 g_string_append(cfg->path.path[PTID_GTKRC], G_DIR_SEPARATOR_S PACKAGE);
298 }
299 else
300 cfg->path.path[PTID_GTKRC] = g_string_new(PATH_GRC);
301 cfg->path.path[PTID_FSTAB] = g_string_new("/etc/fstab");
302 cfg->path.path[PTID_MTAB] = g_string_new("/proc/mounts");
303
304 cfg->path.hideinfo.mode = HIDE_NONE;
305 cfg->path.hideinfo.hide_re_src[0] = '\0';
306 cfg->path.hideinfo.hide_re = NULL;
307 }
308
309 /* ----------------------------------------------------------------------------------------- */
310
311 /* 1998-11-29 - Load the GTK+ RC file, allowing users to configure gentoo's looks. The
312 ** file is always named ".gentoogtkrc" (too long, I know) but you can put
313 ** it anywhere as long as you given gentoo the path (in the config).
314 ** 2001-08-12 - The dot is now optional, but is given priority if found.
315 ** 2011-07-24 - Now we even prefer "gtkrc", without "gentoo", to match .config/gentoo location.
316 ** 2012-05-02 - Ported to use GtkCssProvider API, for GTK+ 3.0.
317 */
load_gtk_rc(MainInfo * min)318 static void load_gtk_rc(MainInfo *min)
319 {
320 const gchar *names[] = { "gtkrc", "gentoogtkrc", ".gentoogtkrc" };
321 const gchar *name;
322 gsize i;
323
324 for(i = 0; i < sizeof names / sizeof *names; i++)
325 {
326 if((name = fut_locate(min->cfg.path.path[PTID_GTKRC]->str, names[i])) != NULL)
327 {
328 GtkCssProvider *prov;
329
330 if((prov = gtk_css_provider_new()) != NULL)
331 {
332 if(gtk_css_provider_load_from_path(prov, name, NULL))
333 {
334 GdkScreen *scr = gtk_widget_get_screen(min->gui->window);
335
336 gtk_style_context_add_provider_for_screen(scr, GTK_STYLE_PROVIDER(prov), GTK_STYLE_PROVIDER_PRIORITY_THEME);
337 break;
338 }
339 }
340 }
341 }
342 }
343
344 /* 1999-04-04 - Initialize default (er, and non-configurable) command options. I'll
345 ** build a GUI for this stuff real soon now.
346 */
init_cmd_options(CfgInfo * cfg)347 static void init_cmd_options(CfgInfo *cfg)
348 {
349 cfg->opt_overwrite.show_info = TRUE;
350 g_strlcpy(cfg->opt_overwrite.datefmt, "%Y-%m-%d %H:%M.%S", sizeof cfg->opt_overwrite.datefmt);
351 }
352
353 #if 0
354 /* 1999-05-10 - This is for temporary key checks during development. Simpler to get a trigger this way
355 ** than to hack the controls and/or keyboard modules. Is that a sign of bad code there? Naah. :)
356 */
357 #include <gdk/gdkkeysyms.h>
358 static void evt_key_press(GtkWidget *wid, GdkEventKey *evt, gpointer user)
359 {
360 MainInfo *min = user;
361
362 printf("Someone pressed %d ('%c'), state=%04X\n", evt->keyval, evt->keyval, evt->state);
363
364 if(evt->keyval == GDK_v)
365 {
366 GtkAdjustment *adj;
367
368 if((adj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(min->gui->cur_pane->scwin))) != NULL)
369 printf("Adj: lower=%g upper=%g value=%g\n", adj->lower, adj->upper, adj->value);
370 }
371 else if(evt->keyval == GDK_z)
372 dp_unfocus(min->gui->cur_pane);
373 else if(evt->keyval == GDK_d)
374 {
375 Dialog *dlg;
376 gint ret;
377
378 dlg = dlg_dialog_sync_new(NULL, "Hello", "_A|_B");
379 ret = dlg_dialog_sync_wait(dlg);
380 dlg_dialog_sync_destroy(dlg);
381 }
382 else if(evt->keyval == GDK_1)
383 {
384 min->cfg.dp_paning.mode++;
385 if(min->cfg.dp_paning.mode > DPSPLIT_ABS_RIGHT)
386 min->cfg.dp_paning.mode = DPSPLIT_FREE;
387 }
388 else if(evt->keyval == GDK_0)
389 gtk_widget_hide(min->gui->pane[0].scwin);
390 else if(evt->keyval == GDK_plus)
391 gtk_widget_show(min->gui->pane[0].scwin);
392 }
393 #endif
394
395 /* 2002-02-19 - Resolve what the initial directory is going to be, and go there. */
enter_initial_dirs(MainInfo * min,const gchar * dirleft,const gchar * dirright)396 static gboolean enter_initial_dirs(MainInfo *min, const gchar *dirleft, const gchar *dirright)
397 {
398 const gchar *dir;
399 const gchar *odir[2];
400 const gchar *cmd[] = { "ActivateLeft", "ActivateRight" };
401 gint i;
402 gboolean ok = TRUE;
403
404 odir[0] = dirleft;
405 odir[1] = dirright;
406 for(i = sizeof cmd / sizeof *cmd - 1; i >= 0; i--)
407 {
408 if((dir = odir[i]) == NULL)
409 {
410 dir = min->cfg.dp_format[i].def_path;
411 if(!dir[0])
412 dir = dph_history_get_first(&min->gui->pane[i]);
413 }
414 if(dir == NULL)
415 dir = usr_get_home();
416 csq_execute(min, cmd[i]);
417 ok &= csq_execute_format(min, "DirEnter 'dir=%s'", stu_escape(dir)) != 0;
418 }
419
420 return ok;
421 }
422
423 /* 2003-11-25 - An idle handler that should only trigger once, to run commands from command line. */
evt_idle_run(gpointer user)424 static gint evt_idle_run(gpointer user)
425 {
426 MainInfo *min = user;
427
428 if(min->run_commands != NULL)
429 {
430 gsize i;
431
432 for(i = 0; min->run_commands[i] != NULL; i++)
433 csq_execute(min, min->run_commands[i]);
434 }
435
436 return FALSE; /* Causes the handler to be removed, once really is enough. */
437 }
438
cmp_list_commands(gconstpointer a,gconstpointer b)439 static gint cmp_list_commands(gconstpointer a, gconstpointer b)
440 {
441 return strcmp(a, b);
442 }
443
cb_list_commands(gpointer key,gpointer value,gpointer user)444 static void cb_list_commands(gpointer key, gpointer value, gpointer user)
445 {
446 GList **head = user;
447
448 *head = g_list_insert_sorted(*head, key, cmp_list_commands);
449 }
450
do_list_commands(MainInfo * min)451 static void do_list_commands(MainInfo *min)
452 {
453 GList *cmdseq = NULL, *iter;
454
455 g_hash_table_foreach(min->cfg.commands.builtin, cb_list_commands, &cmdseq);
456 for(iter = cmdseq; iter != NULL; iter = g_list_next(iter))
457 printf("%s\n", (const gchar *) iter->data);
458 }
459
main(int argc,char * argv[])460 int main(int argc, char *argv[])
461 {
462 static MainInfo min = { NULL };
463
464 gboolean show_version = FALSE;
465 gboolean root_ok = FALSE;
466 gboolean no_rc = FALSE, no_gtk_rc = FALSE, no_dir_history = FALSE, list_commands = FALSE;
467 gchar *dir_left = NULL;
468 gchar *dir_right = NULL;
469 #if defined ENABLE_NLS
470 gboolean show_locale_info = FALSE;
471 gint i;
472 #endif
473 GOptionEntry option_entries[] = {
474 { "version", 0, 0, G_OPTION_ARG_NONE, &show_version, N_("Report the version to standard output, and exit"), NULL },
475 #if defined ENABLE_NLS
476 { "locale-info", 0, 0, G_OPTION_ARG_NONE, &show_locale_info, N_("Report internal locale details, and exit"), NULL },
477 #endif
478 { "root-ok", 0, 0, G_OPTION_ARG_NONE, &root_ok, N_("Allows gentoo to be run by the root user. Could be dangerous!"), NULL },
479 { "no-rc", 0, 0, G_OPTION_ARG_NONE, &no_rc, N_("Do not load the ~/.config/gentoo/gentoorc configuration file; instead, use default values"), NULL },
480 { "no-gtk-rc", 0, 0, G_OPTION_ARG_NONE, &no_gtk_rc, N_("Do not load the ~/.config/gentoo/gtkrc GTK+ configuration file; instead, use system defaults"), NULL },
481 { "no-dir-history", 0, 0, G_OPTION_ARG_NONE, &no_dir_history, N_("Do not load the ~/.config/gentoo/dirhistory file; instead, start with empty history"), NULL },
482 { "run", 'r', 0, G_OPTION_ARG_STRING_ARRAY, &min.run_commands, N_("Run COMMAND, a gentoo command. Done before user interaction allowed, but after configuration "
483 "file has been read in. Can be used many times to run several commands in sequence"), N_("COMMAND") },
484 { "left", '1', 0, G_OPTION_ARG_STRING, &dir_left, N_("Use DIR as path for the left directory pane. Overrides default (and history)"), N_("DIR") },
485 { "right", '2', 0, G_OPTION_ARG_STRING, &dir_right, N_("Use DIR as path for the right directory pane. Overrides default (and history)"), N_("DIR") },
486 { "list-commands", 0, 0, G_OPTION_ARG_NONE, &list_commands, N_("Print a list of all built-in commands, and exit"), NULL },
487 { NULL }
488 };
489 GtkWidget *box;
490 GOptionContext *context;
491 GError *err = NULL;
492
493 #if defined ENABLE_NLS
494 setlocale(LC_ALL, "");
495 bindtextdomain(PACKAGE, LOCALEDIR);
496 textdomain(PACKAGE);
497 /* Translate help texts for command line options. */
498 for(i = 0; option_entries[i].long_name != NULL; i++)
499 {
500 option_entries[i].description = _(option_entries[i].description);
501 option_entries[i].arg_description = _(option_entries[i].arg_description);
502 }
503 #endif
504
505 /* Use glib's option parser, for consistency, features and just less code in general. Nice. */
506 context = g_option_context_new(_("- a graphical file manager using GTK+"));
507 g_option_context_add_main_entries(context, option_entries, PACKAGE);
508 g_option_context_add_group(context, gtk_get_option_group(TRUE)); /* Import GTK+'s options. */
509 if(!g_option_context_parse(context, &argc, &argv, &err))
510 {
511 g_print(_("Failed to parse command line options: %s\n"), err->message);
512 return EXIT_FAILURE;
513 }
514
515 /* Must be run before application-level options parsing. */
516 gtk_init(&argc, &argv);
517
518 min.vfs.vfs = g_vfs_get_default();
519
520 if(show_version)
521 {
522 puts(VERSION);
523 return EXIT_SUCCESS;
524 }
525 #if defined ENABLE_NLS
526 if(show_locale_info)
527 {
528 const gchar *enc, *cset, **fenc;
529
530 printf("PACKAGE=\"%s\"\n", PACKAGE);
531 printf("LOCALEDIR=\"%s\"\n", LOCALEDIR);
532
533 enc = g_getenv("G_FILENAME_ENCODING");
534 if(enc == NULL)
535 enc = "(not set)";
536 printf("G_FILENAME_ENCODING=\"%s\"\n", enc);
537
538 g_get_filename_charsets(&fenc);
539 printf("Filename encoding: \"%s\"\n", (fenc != NULL && *fenc != NULL) ? *fenc : "(unknown)");
540
541 g_get_charset(&cset);
542 if(cset == NULL)
543 cset = "(unknown)";
544 printf("Native charset: \"%s\"\n", cset);
545 return EXIT_SUCCESS;
546 }
547 #endif
548
549 if(geteuid() == 0 && !root_ok)
550 {
551 fprintf(stderr, _("%s: To allow running as root, use the '--root-ok' option\n"), argv[0]);
552 return EXIT_FAILURE;
553 }
554
555 dpf_initialize();
556 mnu_initialize();
557
558 min.cfg.flags = 0;
559 dpf_init_defaults(&min.cfg);
560 csq_init_commands(&min);
561
562 if(list_commands)
563 {
564 do_list_commands(&min);
565 return EXIT_SUCCESS;
566 }
567
568 min.cfg.menus = mnu_menuinfo_new_default(&min);
569 btn_buttoninfo_new_default(&min, &min.cfg.buttons);
570 min.cfg.buttonlayout = btl_buttonlayout_new();
571 init_paths(&min.cfg);
572 min.cfg.style = stl_styleinfo_default();
573 typ_init(&min.cfg);
574 min.cfg.wininfo = win_wininfo_new_default(&min);
575 min.cfg.ctrlinfo = ctrl_new_default(&min);
576 min.cfg.errors.display = ERR_DISPLAY_STATUSBAR;
577 cng_initialize(&min.cfg.nag);
578 min.cfg.dir_filter = dir_filter;
579 chd_initialize(&min);
580 min.que = que_initialize();
581
582 min.ico = ico_initialize(&min);
583
584 min.cfg.flags = 0;
585 if(!no_rc)
586 cfg_load_config(&min);
587 if(!usr_init())
588 g_warning(_("Couldn't initialize userinfo module - username resolving won't work"));
589
590 if((box = build_gui(&min)) != NULL)
591 {
592 dp_initialize(min.gui->pane, sizeof min.gui->pane / sizeof *min.gui->pane);
593
594 if(!no_gtk_rc)
595 load_gtk_rc(&min);
596
597 fam_initialize(&min);
598
599 dlg_main_window_set(GTK_WINDOW(min.gui->window));
600 dlg_position_set(min.cfg.dialogs.pos);
601 #if 0
602 g_signal_connect(G_OBJECT(min.gui->window), "key_press_event", G_CALLBACK(evt_key_press), &min);
603 #endif
604 init_cmd_options(&min.cfg);
605
606 gtk_container_add(GTK_CONTAINER(min.gui->window), box);
607
608 if(!no_dir_history)
609 dph_history_load(&min, min.gui->pane, sizeof min.gui->pane / sizeof *min.gui->pane);
610
611 gtk_window_set_resizable(GTK_WINDOW(min.gui->window), TRUE);
612
613 win_window_show(min.gui->window);
614
615 err_clear(&min);
616 if(enter_initial_dirs(&min, dir_left, dir_right))
617 {
618 if(min.gui->top != NULL)
619 {
620 gchar buf[128];
621
622 g_snprintf(buf, sizeof buf, _("gentoo v%s by Emil Brink <emil@obsession.se>"), VERSION);
623 gtk_label_set_text(GTK_LABEL(min.gui->top), buf);
624 }
625 }
626 else
627 err_show(&min);
628
629 ndl_dialog_sync_new_wait(&min, "gio-warning", _("Development Version Warning"), _("This version of gentoo is considered somewhat new and untested.\nThere have been major changes to almost all parts of the program since the previous version.\nPlease be a bit careful, and make sure you report any problem to the author. Thanks."));
630
631 g_idle_add(evt_idle_run, &min);
632 gtk_main();
633 }
634 chd_kill_children();
635 fam_shutdown(&min);
636
637 return EXIT_SUCCESS;
638 }
639