1 #ifdef COPYRIGHT_INFORMATION
2 #include "gplv3.h"
3 #endif
4 /*
5 * Copyright (C) 2002-2012 Edscott Wilson Garcia
6 * EMail: edscott@users.sf.net
7 *
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; */
21
22 static void *
done_with_rename(gpointer data)23 done_with_rename (gpointer data) {
24 widgets_t *widgets_p = data;
25 if (rfm_get_gtk_thread() != g_thread_self()){
26 g_warning("done_with_rename() is a main thread function\n");
27 return NULL;
28 }
29 view_t *view_p = widgets_p->view_p;
30 gchar *path;
31 NOOP ("rodent_done_with_rename\n");
32 if(!view_p->widgets.rename) {
33 NOOP ("!view_p->widgets.rename\n");
34 return NULL;
35 }
36 path = g_object_get_data (G_OBJECT (view_p->widgets.rename), "path");
37 g_free (path);
38
39
40 NOOP ("gtk_widget_destroy(GTK_WIDGET(view_p->widgets.rename));\n");
41 gtk_widget_destroy (GTK_WIDGET (view_p->widgets.rename));
42
43 view_p->widgets.rename = NULL;
44 gtk_main_quit();
45 rodent_unselect_all_pixbuf (view_p);
46 return NULL;
47 }
48
49
50 ///////////////////////////// ENTRY rename/copy/simlink /////////////////
51 //
52
53 static int
entry_rename(widgets_t * widgets_p,const gchar * nfile,const gchar * ofile)54 entry_rename (widgets_t * widgets_p, const gchar * nfile, const gchar * ofile) {
55 fprintf (stderr,"entry_rename: %s --> %s\n", ofile, nfile);//OK
56 if(!widgets_p || !nfile || !ofile || !strlen (nfile) || !strlen (ofile))
57 return FALSE;
58
59 GList *in_list = NULL;
60 gchar *src = g_strdup(ofile);
61 in_list = g_list_append (in_list, src);
62
63 plain_cp (widgets_p, TR_MOVE, in_list, nfile, FALSE);
64 g_list_free (in_list);
65 g_free(src);
66 view_t *view_p = widgets_p->view_p;
67 if (!xfdir_monitor_control_greenlight(widgets_p)){
68 rodent_trigger_reload(view_p);
69 }
70
71
72 return TRUE;
73 }
74
75 static int
entry_duplicate(widgets_t * widgets_p,const gchar * nfile,const gchar * ofile)76 entry_duplicate (widgets_t * widgets_p, const gchar * nfile, const gchar * ofile) {
77 if(!widgets_p || !nfile || !ofile || !strlen (nfile) || !strlen (ofile))
78 return FALSE;
79
80 GList *in_list = NULL;
81 gchar *src = g_strdup(ofile);
82 in_list = g_list_append (in_list, src);
83 plain_cp (widgets_p, TR_COPY, in_list, nfile, FALSE);
84 g_list_free (in_list);
85 g_free(src);
86 view_t *view_p = widgets_p->view_p;
87 if (!xfdir_monitor_control_greenlight(widgets_p)){
88 rodent_trigger_reload(view_p);
89 }
90
91
92
93 return TRUE;
94 }
95
96 static int
entry_symlink(widgets_t * widgets_p,const gchar * nfile,const gchar * ofile)97 entry_symlink (widgets_t * widgets_p, const gchar * nfile, const gchar * ofile) {
98
99 if(!widgets_p || !nfile || !ofile || !strlen (nfile) || !strlen (ofile))
100 return FALSE;
101
102 #if 1
103 g_free(widgets_p->workdir);
104 // Relative links, always...
105 widgets_p->workdir=g_path_get_dirname(ofile);
106 gboolean need_sudo = !rfm_write_ok_path(widgets_p->workdir);
107
108 gchar *b_ofile=g_path_get_basename(ofile);
109 gchar *b_nfile=g_path_get_basename(nfile);
110 gchar *sources[]={"ln", "-s", b_ofile, b_nfile, NULL};
111 if (need_sudo){
112 gchar *failed=g_strdup_printf(_("Failed to link %s to %s"),
113 _("File"), _("Destination"));
114 if (confirm_sudo(widgets_p, widgets_p->workdir, failed, "ln")){
115 RFM_TRY_SUDO (widgets_p, sources, FALSE);
116 }
117 g_free (failed);
118 } else {
119 rfm_thread_run_argv (widgets_p, sources, FALSE);
120 }
121 g_free(b_ofile);
122 g_free(b_nfile);
123
124 #else
125 // oldway (no sudo)
126 g_free(widgets_p->workdir);
127 // Relative links, always...
128 widgets_p->workdir=g_path_get_dirname(ofile);
129 gchar *b_ofile=g_path_get_basename(ofile);
130 gchar *b_nfile=g_path_get_basename(nfile);
131 gchar *command = g_strdup_printf ("ln -s \"%s\" \"%s\"", b_ofile, b_nfile);
132 RFM_THREAD_RUN2ARGV (widgets_p, command, FALSE);
133 g_free (command);
134 g_free(b_ofile);
135 g_free(b_nfile);
136 #endif
137
138
139 view_t *view_p = widgets_p->view_p;
140 if (!xfdir_monitor_control_greenlight(widgets_p)){
141 rodent_trigger_reload(view_p);
142 }
143
144
145
146 return TRUE;
147 }
148
149 static void
entry_activate(GtkEntry * entry,view_t * view_p,int caso)150 entry_activate (GtkEntry * entry, view_t * view_p, int caso) {
151 gchar *actual_tag;
152 gchar *tag;
153 gchar *b;
154 int result = FALSE;
155 gchar *path;
156 widgets_t *widgets_p=&(view_p->widgets);
157
158 if (view_p->widgets.rename) gtk_widget_hide (GTK_WIDGET (view_p->widgets.rename));
159
160 path = g_object_get_data (G_OBJECT (view_p->widgets.rename), "path");
161 if(!path) return;
162
163 actual_tag = gtk_editable_get_chars ((GtkEditable *) entry, 0, -1);
164 g_strstrip(actual_tag);
165 tag = g_locale_from_utf8 (actual_tag, -1, NULL, NULL, NULL);
166 g_free (actual_tag);
167 actual_tag = tag;
168 b = g_path_get_basename (path);
169
170 gchar *d = g_path_get_dirname (path);
171 gchar *p = g_build_filename (d, actual_tag, NULL);
172 g_free (d);
173 switch (caso) {
174 case RENAME_CASO:
175 result = entry_rename (widgets_p, p, path);
176 if(result) {
177 NOOP ("renaming %s to %s\n", path, p);
178 }
179 break;
180 case DUPLICATE_CASO:
181 result = entry_duplicate (widgets_p, p, path);
182 if(result) {
183 NOOP ("duplication %s to %s\n", path, p);
184 }
185 break;
186 case SYMLINK_CASO:
187 result = entry_symlink (widgets_p, p, path);
188 if(result) {
189 NOOP ("symlinking %s to %s\n", path, p);
190 }
191 break;
192 }
193 g_free (p);
194
195 g_free (b);
196 g_free (actual_tag);
197 done_with_rename (widgets_p);
198 }
199
200 static void
entry_activate_rename(GtkEntry * entry,gpointer data)201 entry_activate_rename (GtkEntry * entry, gpointer data) {
202 entry_activate (entry, (view_t *) data, 0);
203 }
204
205 static void
entry_activate_duplicate(GtkEntry * entry,gpointer data)206 entry_activate_duplicate (GtkEntry * entry, gpointer data) {
207 entry_activate (entry, (view_t *) data, 1);
208 }
209
210 static void
entry_activate_symlink(GtkEntry * entry,gpointer data)211 entry_activate_symlink (GtkEntry * entry, gpointer data) {
212 entry_activate (entry, (view_t *) data, 2);
213 }
214
215 static void
destroy_dialog(GtkWidget * widget,gpointer data)216 destroy_dialog (GtkWidget * widget, gpointer data) {
217 widgets_t *widgets_p = data;
218 done_with_rename (widgets_p);
219 }
220
221 static gint
on_key_press(GtkWidget * entry,GdkEventKey * event,gpointer data)222 on_key_press (GtkWidget * entry, GdkEventKey * event, gpointer data) {
223 if(event->keyval == GDK_KEY_Escape) {
224 widgets_t *widgets_p = data;
225 done_with_rename (widgets_p);
226 //rfm_status (&(view_p->widgets), NULL, _("Omitting"), NULL);
227 return TRUE;
228 }
229 return FALSE;
230 }
231
232 static gboolean
grab_focus(GtkWidget * widget,GdkEventCrossing * event,gpointer data)233 grab_focus (GtkWidget * widget, GdkEventCrossing * event, gpointer data) {
234 rfm_global_t *rfm_global_p = rfm_global();
235 XSetInputFocus (rfm_global_p->Xdisplay,
236 GDK_WINDOW_XID (gtk_widget_get_parent_window (widget)), RevertToParent, CurrentTime);
237 XUngrabPointer (rfm_global_p->Xdisplay, CurrentTime);
238 return TRUE;
239 }
240
241 static void
entry_aid(view_t * view_p,gint caso,gint labelY)242 entry_aid(view_t *view_p, gint caso, gint labelY){
243 GtkWidget *vpane = g_object_get_data(G_OBJECT(view_p->widgets.paper), "vpane");
244 if (vpane==NULL) return;
245
246 GtkAllocation allocation;
247 gtk_widget_get_allocation (vpane, &allocation);
248
249 NOOP( "ENTRY population_p->labelY = %d, position=%lf\n",
250 labelY, allocation.height * 0.75);
251 if (labelY < allocation.height * 0.70){
252 rfm_show_text(&(view_p->widgets));
253 } else return;
254
255 switch (caso) {
256 case 0:
257 rfm_diagnostics(&(view_p->widgets),"xffm/stock_dialog-info",NULL);
258
259 rfm_diagnostics(&(view_p->widgets),"xffm_tag/green",
260 _("Rename the selected file"), "--> ", NULL);
261 rfm_diagnostics(&(view_p->widgets),"xffm_tag/red",
262 _("Click"), "\n", NULL);
263
264 rfm_diagnostics(&(view_p->widgets),"xffm_tag/grey",
265 _("Duplicate this path"), "--> ", NULL);
266 rfm_diagnostics(&(view_p->widgets),"xffm_tag/grey",_
267 ("Control"),"+",_("Click"), "\n", NULL);
268
269 rfm_diagnostics(&(view_p->widgets),"xffm_tag/grey",
270 _("Create Symlink"), "--> ", NULL);
271 rfm_diagnostics(&(view_p->widgets),"xffm_tag/grey",
272 _("Shift"),"+",_("Control"),"+", _("Click"), "\n", NULL);
273 break;
274 case 1:
275 rfm_diagnostics(&(view_p->widgets),"xffm/stock_dialog-info",NULL);
276 rfm_diagnostics(&(view_p->widgets),"xffm_tag/green",
277 _("Duplicate this path"), "--> ", NULL);
278 rfm_diagnostics(&(view_p->widgets),"xffm_tag/red",_
279 ("Control"),"+",_("Click"), "\n", NULL);
280
281 rfm_diagnostics(&(view_p->widgets),"xffm_tag/grey",
282 _("Rename the selected file"), "--> ", NULL);
283 rfm_diagnostics(&(view_p->widgets),"xffm_tag/grey",
284 _("Click"), "\n", NULL);
285
286 rfm_diagnostics(&(view_p->widgets),"xffm_tag/grey",
287 _("Create Symlink"), "--> ", NULL);
288 rfm_diagnostics(&(view_p->widgets),"xffm_tag/grey",
289 _("Shift"),"+",_("Control"),"+", _("Click"), "\n", NULL);
290 break;
291 case 2:
292 rfm_diagnostics(&(view_p->widgets),"xffm/stock_dialog-info",NULL);
293 rfm_diagnostics(&(view_p->widgets),"xffm_tag/green",
294 _("Create Symlink"), "--> ", NULL);
295 rfm_diagnostics(&(view_p->widgets),"xffm_tag/red",
296 _("Shift"),"+",_("Control"),"+", _("Click"), "\n", NULL);
297
298 rfm_diagnostics(&(view_p->widgets),"xffm_tag/grey",
299 _("Rename the selected file"), "--> ", NULL);
300 rfm_diagnostics(&(view_p->widgets),"xffm_tag/grey",
301 _("Click"), "\n", NULL);
302
303 rfm_diagnostics(&(view_p->widgets),"xffm_tag/grey",
304 _("Duplicate this path"), "--> ", NULL);
305 rfm_diagnostics(&(view_p->widgets),"xffm_tag/grey",_
306 ("Control"),"+",_("Click"), "\n", NULL);
307
308 break;
309 }
310 }
311
312 /* entry function: */
313 static void *
mk_rename_entry(gpointer data)314 mk_rename_entry (gpointer data) {
315 rfm_global_t *rfm_global_p = rfm_global();
316 void **arg = data;
317 view_t *view_p = arg[0];
318 const population_t *population_p = arg[1];
319 gint caso = GPOINTER_TO_INT(arg[2]);
320 g_free(arg);
321 GdkRectangle label_rect;
322 if (!rfm_get_population_label_rect_full(view_p, population_p, &label_rect)) return NULL;
323
324 GtkWidget *entry;
325 GtkWidget *hbox;
326
327 //widgets_t *widgets_p=&(view_p->widgets);
328
329 GdkRectangle frame_extent;
330 GdkRectangle window_extent;
331
332 gint delta_y;
333 gint delta_h;
334 gint y_offset;
335 gdk_window_get_position (gtk_widget_get_window(rfm_global_p->window),
336 &window_extent.x, &window_extent.y);
337 Drawable drawable =
338 GDK_WINDOW_XID(gtk_widget_get_window(rfm_global_p->window));
339 rfm_get_drawable_geometry(drawable, NULL, NULL, &window_extent.width, &window_extent.height, NULL);
340 NOOP("window_geometry: x=%d, y=%d, w=%d, h=%d", window_extent.x, window_extent.y, window_extent.width, window_extent.height);
341
342 gdk_window_get_frame_extents (gtk_widget_get_window(rfm_global_p->window),&frame_extent);
343 NOOP("window_frame_extents: x=%d, y=%d, w=%d, h=%d\n",
344 frame_extent.x, frame_extent.y, frame_extent.width, frame_extent.height);
345
346
347 delta_y = window_extent.y - frame_extent.y;
348 delta_h = frame_extent.height - window_extent.height;
349 y_offset = delta_y + delta_h;
350 NOOP("window: delta_y=%d, delta_h=%d, y_offset=%d\n",
351 delta_y, delta_h, y_offset);
352
353
354 NOOP ("rodent_mk_text_entry...\n");
355 if(!population_p || !population_p->en || !population_p->en->path){
356 NOOP(stderr, "rodent_mk_text_entry: invalid population\n");
357 return NULL;
358 }
359
360 /* caso=0, rename; caso=1, duplicate; caso=2, symlink */
361
362 entry = gtk_entry_new ();
363 hbox = rfm_hbox_new (FALSE, 0);
364 view_p->widgets.rename = gtk_window_new (GTK_WINDOW_POPUP);
365
366 gint x_coordinate;
367 gint y_coordinate;
368 /* change relative coordinates to absolute coordinates and place entry window */
369 {
370 double sh=0;
371 GtkScrolledWindow *scrolled_window = g_object_get_data(G_OBJECT(view_p->widgets.paper), "scrolled_window");
372 if(scrolled_window && GTK_IS_SCROLLED_WINDOW (scrolled_window)) {
373 sh = gtk_adjustment_get_value (gtk_scrolled_window_get_vadjustment (scrolled_window));
374 }
375 gtk_window_get_position ((GtkWindow *) rfm_global_p->window, &x_coordinate, &y_coordinate);
376 x_coordinate += ((frame_extent.width - window_extent.width)/2);
377 y_coordinate = label_rect.y + frame_extent.y - sh
378 + y_offset + TEXTSPACING;
379 gtk_window_move ((GtkWindow *) view_p->widgets.rename,
380 label_rect.x + x_coordinate,
381 y_coordinate);
382
383 }
384
385 gtk_window_set_resizable (GTK_WINDOW (view_p->widgets.rename), FALSE);
386 gtk_container_set_border_width (GTK_CONTAINER (view_p->widgets.rename), 0);
387 gtk_window_set_modal (GTK_WINDOW (view_p->widgets.rename), FALSE);
388
389 gchar *g = NULL;
390 gchar *b = g_path_get_basename (population_p->en->path);
391 gchar *path = g_strdup (population_p->en->path);
392 g_object_set_data (G_OBJECT (view_p->widgets.rename), "path", path);
393 g_object_set_data (G_OBJECT (view_p->widgets.rename), "caso", GINT_TO_POINTER(caso));
394
395 if(caso == 0) {
396 g = g_strdup (b);
397 rfm_status (&(view_p->widgets), "xffm/stock_dialog-warning", b, ": ", _("Rename"), "...", NULL);
398 g_signal_connect (G_OBJECT (entry), "activate", G_CALLBACK (entry_activate_rename), view_p);
399 NOOP(stderr, "Rename...\n");
400 } else if(caso == 1) {
401 gchar *dir = g_path_get_dirname (population_p->en->path);
402 g = g_strdup_printf (_("Copy of %s"), b);
403 g_free (dir);
404 rfm_status (&(view_p->widgets), "xffm/stock_dialog-warning", b, ": ", _("Duplicate"), "...", NULL);
405 NOOP(stderr, "Duplicate...\n");
406 g_signal_connect (G_OBJECT (entry), "activate", G_CALLBACK (entry_activate_duplicate), view_p);
407 } else if(caso == 2) {
408 g = g_strdup_printf (_("Link to %s"), b);
409 rfm_status (&(view_p->widgets), "xffm/stock_dialog-warning", b, ": ", _("Create Symbolic Link"), "...", NULL);
410 NOOP(stderr, "Symlink...\n");
411 g_signal_connect (G_OBJECT (entry), "activate", G_CALLBACK (entry_activate_symlink), view_p);
412 }
413 gchar *q = rfm_utf_string (g);
414 gchar *p=q;
415 double extra=0;
416
417 while (p && *p) { //hack: gtk bug workaround
418 gunichar up=g_utf8_get_char_validated (p, -1);
419 if (up > 0) {
420 if (g_unichar_isupper(up)) extra += 0.3;
421 //if (g_unichar_islower(up)) extra -= 0.1;
422 if (g_unichar_iswide(up)) extra += 1.0;
423 if (g_unichar_ispunct(up)) extra -= 0.2;
424 if (g_unichar_iszerowidth(up)) extra -= 1.0;
425 }
426 p++;
427 }
428 extra += 0.5;
429 int chars = extra + g_utf8_strlen (q, -1);
430 if (chars < 7) chars=7;
431
432 gtk_entry_set_width_chars ((GtkEntry *)entry, chars);
433 gtk_entry_set_text ((GtkEntry *) entry, q);
434 g_free (q);
435 g_free (b);
436 g_free (g);
437
438 gtk_editable_set_editable ((GtkEditable *) entry, TRUE);
439
440 gtk_container_set_border_width (GTK_CONTAINER (hbox), 0);
441 gtk_container_add (GTK_CONTAINER (view_p->widgets.rename), hbox);
442
443 gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, FALSE, 0);
444
445 g_signal_connect (G_OBJECT (view_p->widgets.rename), "destroy-event", G_CALLBACK (destroy_dialog), &(view_p->widgets));
446 g_signal_connect (G_OBJECT (view_p->widgets.rename), "key_press_event", G_CALLBACK (on_key_press), &(view_p->widgets));
447 g_signal_connect (G_OBJECT (view_p->widgets.rename), "delete-event", G_CALLBACK (destroy_dialog), &(view_p->widgets));
448
449
450 g_signal_connect (G_OBJECT (entry), "enter-notify-event", G_CALLBACK (grab_focus), view_p);
451 entry_aid(view_p, caso, label_rect.y);
452 NOOP ("now showing view_p->widgets.rename \n");
453 gtk_widget_show_all (view_p->widgets.rename);
454 gint endpos;
455 g = gtk_editable_get_chars ((GtkEditable *) entry, 0, -1);
456 if(strchr (g, '.')) {
457 gtk_editable_select_region ((GtkEditable *) entry, 0, 0);
458 for(endpos = strlen (g) - 1; g[endpos] >= 0; endpos--) {
459 if(g[endpos] == '.')
460 break;
461 }
462 NOOP ("entry box: endpos=%d\n", endpos);
463 gtk_editable_select_region ((GtkEditable *) entry, 0, endpos);
464 }
465 g_free (g);
466
467 /* this sucks: gtk_widget_grab_focus (view_p->widgets.rename); */
468 XSetInputFocus (rfm_global_p->Xdisplay,
469 GDK_WINDOW_XID (gtk_widget_get_parent_window (entry)), RevertToParent, CurrentTime);
470
471 gtk_window_set_transient_for (GTK_WINDOW (view_p->widgets.rename), GTK_WINDOW (rfm_global_p->window));
472
473 rfm_get_drawable_geometry(rfm_global_p->root_Xwindow, NULL, NULL, &window_extent.width, &window_extent.height, NULL);
474
475
476 //test 1, is the box larger than the root window?
477 GtkAllocation allocation;
478 gtk_widget_get_allocation (view_p->widgets.rename, &allocation);
479
480 if (allocation.width > window_extent.width) {
481 gtk_widget_set_size_request(entry, window_extent.width-6, -1);
482 gtk_widget_set_size_request(view_p->widgets.rename, window_extent.width, -1);
483 x_coordinate=0;
484 // this does not do what I think it should do (show start of truncated text):
485 //gtk_entry_set_alignment((GtkEntry *)entry, 0);
486 } else { // it fits, try to place it.
487 int center = x_coordinate + label_rect.x;
488 // overspill?
489 if (center + allocation.width > window_extent.width) x_coordinate = window_extent.width - allocation.width;
490 // center is OK
491 else x_coordinate=center;
492 }
493
494
495 gtk_window_move ((GtkWindow *) view_p->widgets.rename,
496 x_coordinate, //
497 y_coordinate);
498 XGrabPointer (rfm_global_p->Xdisplay,
499 GDK_WINDOW_XID (gtk_widget_get_parent_window (entry)),
500 TRUE, 0, GrabModeSync, GrabModeAsync,
501 GDK_WINDOW_XID (gtk_widget_get_parent_window (entry)),
502 None, CurrentTime);
503 XUngrabPointer(rfm_global_p->Xdisplay,CurrentTime);
504 gtk_main();
505 return NULL;
506 }
507
508
509