1 /*
2  * Copyright (C) 2002-2012 Edscott Wilson Garcia
3  * EMail: edscott@users.sf.net
4  *
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program;
18  */
19 /**  miscelaneous */
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23 
24 #define EXPAND      TRUE
25 #define FILL        TRUE
26 #define NOEXPAND    FALSE
27 #define NOFILL      FALSE
28 
29 
30 #include "rfm.h"
31 #include "rfm_modules.h"
32 #include "primary-misc.i"
33 
34 static void
checkmenuitem_toggle(GtkWidget * menuitem,void * data)35 checkmenuitem_toggle(GtkWidget *menuitem, void *data){
36     gboolean state = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem));
37     const gchar *markup_id = (state)?"on_label":"off_label";
38     GtkWidget *child = gtk_bin_get_child (GTK_BIN (menuitem));
39     gtk_label_set_markup (GTK_LABEL (child),
40             (const gchar *)(g_object_get_data(G_OBJECT(menuitem), markup_id)));
41     gtk_label_set_markup (GTK_LABEL (child),
42             (const gchar *)(g_object_get_data(G_OBJECT(menuitem), markup_id)));
43 
44 }
45 
46 GtkWidget *
rfm_create_checkmenuitem(const gchar * label,gboolean state)47 rfm_create_checkmenuitem(const gchar *label, gboolean state){
48     GtkWidget *menuitem = gtk_check_menu_item_new_with_label ("");
49     GtkWidget *child = gtk_bin_get_child (GTK_BIN (menuitem));
50     const gchar *markup_id = (state)?"on_label":"off_label";
51     g_object_set_data(G_OBJECT(menuitem), "on_label", g_strdup_printf("<b>%s</b>", label));
52     g_object_set_data(G_OBJECT(menuitem), "off_label", g_strdup_printf("<i>%s</i>", label));
53 
54     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM (menuitem), state);
55     checkmenuitem_toggle(menuitem, NULL);
56     g_signal_connect(G_OBJECT (menuitem), "toggled", G_CALLBACK (checkmenuitem_toggle), NULL);
57     return menuitem;
58 }
59 
60 GtkWidget *
rfm_create_radiomenuitem(const gchar * label,GSList * group)61 rfm_create_radiomenuitem(const gchar *label, GSList *group){
62     GtkWidget *menuitem = gtk_radio_menu_item_new_with_mnemonic (group, label);
63     GtkWidget *child = gtk_bin_get_child (GTK_BIN (menuitem));
64     g_object_set_data(G_OBJECT(menuitem), "on_label", g_strdup_printf("<b>%s</b>", label));
65     g_object_set_data(G_OBJECT(menuitem), "off_label", g_strdup_printf("<i>%s</i>", label));
66 
67     checkmenuitem_toggle(menuitem, NULL);
68     g_signal_connect(G_OBJECT (menuitem), "toggled", G_CALLBACK (checkmenuitem_toggle), NULL);
69     return menuitem;
70 }
71 
72 void
rfm_null_function(void * user_data)73 rfm_null_function (void *user_data) {
74     return ;
75 }
76 // This is a thread function...
77 
78 void
rfm_markup_stdout_f(void * user_data,void * stream,int childFD)79 rfm_markup_stdout_f (void *user_data, void *stream, int childFD) {
80     widgets_t *widgets_p = user_data;
81     char *line;
82     line = (char *)stream;
83     NOOP ("FORK stdout: %s\n", line);
84 
85     if(line[0] == '\n') return;
86 
87     if(strncmp (line, "Tubo-id exit:", strlen ("Tubo-id exit:")) == 0) {
88 	if(strchr (line, '\n')) *strchr (line, '\n') = 0;
89 	rfm_threaded_diagnostics (widgets_p, "xffm/stock_no", NULL);
90 	rfm_context_function(rfm_scroll_to_top, widgets_p);
91     } else {
92 	if (strchr(line, 0x0d)){
93             *strchr(line, 0x0d) = ' ';// ^M
94         }
95 
96 	if (strchr(line, '-')){
97 	    gchar buffer[256*10];
98 	    memset (buffer, 0, 256*10);
99 	    gint i;
100 	    gint j;
101 	    gboolean on=FALSE;
102 	    for (j=0,i=0; i<255; i++,j++){
103 		if (!on && (line[i] == '-' || line[i] == '[')){
104 		    buffer[j++] = 27;
105 		    buffer[j++] = '[';
106 		    buffer[j++] = '1';
107 		    buffer[j++] = 'm';
108 		    on = TRUE;
109 		}
110 		if (on && (line[i] == ' ' || line[i] == ')' || line[i] == '\t')){
111 		    buffer[j++] = 27;
112 		    buffer[j++] = '[';
113 		    buffer[j++] = '0';
114 		    buffer[j++] = 'm';
115 		    on = FALSE;
116 		}
117 		buffer[j] = line[i];
118 		if (line[i] == 0) break;
119 	    }
120 	    rfm_threaded_diagnostics (widgets_p, NULL, g_strdup(buffer));
121 	} else {
122 	    rfm_threaded_diagnostics (widgets_p, NULL, g_strdup(line));
123 	}
124     }
125     return;
126 }
127 
128 
129 void *
rfm_scroll(widgets_t * widgets_p,gboolean up,gboolean page)130 rfm_scroll(widgets_t *widgets_p, gboolean up, gboolean page){
131     GtkTextBuffer *buffer;
132     buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW ((widgets_p->diagnostics)));
133     gint lines = gtk_text_buffer_get_line_count (buffer);
134     NOOP(stderr, "lines+%d\n", lines);
135     GtkTextIter iter;
136     GtkTextMark *mark = gtk_text_buffer_get_mark (buffer, "scrollmark2");
137 
138     if (mark == NULL){
139 	gtk_text_buffer_get_iter_at_line (buffer,&iter,lines);
140 	mark = gtk_text_buffer_create_mark (buffer, "scrollmark2", &iter, FALSE);
141     }
142 
143     gtk_text_buffer_get_iter_at_mark  (buffer,&iter, mark);
144 
145     gint line_count = 0;
146     while (!gtk_text_view_move_mark_onscreen (GTK_TEXT_VIEW ((widgets_p->diagnostics)),mark)){
147 	if (up) {
148 	    if (!gtk_text_iter_backward_visible_line (&iter)) break;
149 	} else {
150 	    if (!gtk_text_iter_forward_visible_line (&iter)) break;
151 	}
152 	line_count++;
153 	gtk_text_buffer_move_mark   (buffer,  mark  ,&iter);
154     }
155 
156     if (up) {
157 	gtk_text_iter_backward_lines (&iter, (page)?line_count:1);
158     } else {
159 	gtk_text_iter_forward_lines (&iter, (page)?line_count:1);
160     }
161 
162     gtk_text_buffer_move_mark   (buffer,  mark  ,&iter);
163 
164     gtk_text_view_scroll_mark_onscreen  (GTK_TEXT_VIEW ((widgets_p->diagnostics)), mark);
165     //gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW ((widgets_p->diagnostics)), mark, 0.0,
166       //                            TRUE, 0.0, 0.0);
167     //gtk_text_buffer_delete_mark (buffer, mark);
168     return NULL;
169 }
170 
171 void *
rfm_scroll_to_top(void * data)172 rfm_scroll_to_top(void *data){
173     widgets_t *widgets_p = data;
174     GtkTextMark *mark;
175     GtkTextIter start, end;
176     GtkTextBuffer *buffer;
177     buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW ((widgets_p->diagnostics)));
178     gtk_text_buffer_get_bounds (buffer, &start, &end);
179     mark = gtk_text_buffer_create_mark (buffer, "scrollmark", &start, FALSE);
180     gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW ((widgets_p->diagnostics)), mark, 0.2,    /*gdouble within_margin, */
181                                   FALSE, 0.0, 0.0);
182     gtk_text_buffer_delete_mark (buffer, mark);
183     return NULL;
184 }
185 
186 record_entry_t *
rfm_find_in_selection_list(view_t * view_p,record_entry_t * population_en)187 rfm_find_in_selection_list(view_t *view_p, record_entry_t *population_en){
188     if (!view_p->selection_list) return FALSE;
189     record_entry_t *found=NULL;
190     GSList *tmp=view_p->selection_list;
191     for (; tmp && tmp->data; tmp=tmp->next){
192 	record_entry_t *en=tmp->data;
193 	if (!en || !population_en ||
194 		!en->path || !population_en->path) continue;
195 	if (strcmp(en->path, population_en->path)==0){
196 	    found=tmp->data;
197 	    break;
198 	}
199     }
200     return found;
201 }
202 
203 void
rfm_select_pixbuf(view_t * view_p,const population_t * population_p)204 rfm_select_pixbuf (view_t * view_p, const population_t * population_p) {
205      NOOP(stderr, "rfm_select_pixbuf\n");
206     if(!population_p) {
207         NOOP( "rfm_select_pixbuf: !population_p\n");
208         return;
209     }
210     if(!population_p->en) {
211         NOOP( "rfm_select_pixbuf: !population_p->en\n");
212 	return;
213     }
214 
215 
216     if(POPULATION_MODULE(population_p)) {
217         /* ask the POPULATION_MODULE whether the element is selectable
218          * (by default they will not be)*/
219         if(!rfm_natural (PLUGIN_DIR, POPULATION_MODULE(population_p),
220 		    population_p->en, "is_selectable")) {
221 	    NOOP( "rfm_select_pixbuf: !is_selectable\n");
222             return;
223         }
224     }
225     else if(population_p->en && IS_DUMMY_TYPE (population_p->en->type) && !g_path_is_absolute(population_p->en->path)){
226 	    NOOP( "rfm_select_pixbuf: IS_DUMMY_TYPE\n");
227 	return;
228     }
229 
230 
231     if (!(population_p->flags  & POPULATION_SELECTED)) {
232 	((population_t *)population_p)->flags  |= POPULATION_SELECTED;
233     }
234 
235     if (population_p->en && !rfm_find_in_selection_list(view_p, population_p->en)) {
236 	record_entry_t *en=rfm_copy_entry(population_p->en);
237         view_p->selection_list = g_slist_append (view_p->selection_list, en);
238     }
239 
240     view_p->mouse_event.selected_p = population_p;
241 }
242 
243 
244 void
rfm_unselect_pixbuf(view_t * view_p,const population_t * population_p)245 rfm_unselect_pixbuf (view_t * view_p, const population_t * population_p) {
246     NOOP("rfm_unselect_pixbuf: >> unselect_pixbuf\n");
247     if(!population_p) {
248         DBG ("!population_p\n");
249         return;
250     }
251 
252     if (population_p->flags  & POPULATION_SELECTED) {
253 	((population_t *)population_p)->flags  &= (POPULATION_SELECTED ^ 0xffffffff);
254     }
255 
256     record_entry_t *item = rfm_find_in_selection_list(view_p, population_p->en);
257     if(item) {
258         view_p->selection_list = g_slist_remove (view_p->selection_list, item);
259 	rfm_destroy_entry(item);
260         if(!g_slist_length (view_p->selection_list)) {
261             g_slist_free (view_p->selection_list);
262             view_p->selection_list = NULL;
263         }
264     }
265 
266 
267 }
268 
269 static gboolean tooltip_is_mapped = FALSE;
rfm_tooltip_is_mapped(void)270 gboolean rfm_tooltip_is_mapped(void){
271     return tooltip_is_mapped;
272 }
273 
274 static void
tooltip_unmap(GtkWidget * window,gpointer data)275 tooltip_unmap (GtkWidget *window, gpointer data){
276     tooltip_is_mapped = FALSE;
277 
278 }
279 
280 // This is a gtk placement bug workaround. Should probably fix gtk code and
281 // submit the patch: this is a long standing bug...
282 static void
tooltip_map(GtkWidget * window,gpointer data)283 tooltip_map (GtkWidget *window, gpointer data){
284     tooltip_is_mapped = TRUE;
285 }
286 
287 static GdkPixbuf *
shadow_it(const GdkPixbuf * src_pixbuf)288 shadow_it(const GdkPixbuf *src_pixbuf){
289 
290     gint width = gdk_pixbuf_get_width (src_pixbuf);
291     gint height = gdk_pixbuf_get_height (src_pixbuf);
292 
293     gint offset = 7;
294 
295     GdkPixbuf *shadowed =  gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8,
296 	    width + offset, height + offset);
297     if (!shadowed) return NULL;
298 
299     gdk_pixbuf_fill(shadowed, 0x0);
300     gdk_pixbuf_copy_area (src_pixbuf, 0, 0, width, height, shadowed, offset, offset);
301     gdk_pixbuf_saturate_and_pixelate (shadowed, shadowed, 0.0, TRUE);
302                                    // gfloat saturation, gboolean pixelate);
303     gdk_pixbuf_composite (src_pixbuf, shadowed,
304                           0, 0,  //dest_x, dest_y,
305                           width, height,  //dest_width, dest_height,
306 			  0, 0,  //offset_x, offset_y,
307 			  1.0, 1.0, //scale_x, scale_y,
308 			  GDK_INTERP_NEAREST,
309 			  255);   //overall_alpha);
310 
311     return shadowed;
312 }
313 
rfm_set_box_gradient(GtkWidget * wbox)314 void rfm_set_box_gradient(GtkWidget *wbox){
315     // only for gtk+3
316 #if GTK_MAJOR_VERSION==3
317 
318     GtkStyleContext *style_context = gtk_widget_get_style_context (wbox);
319     gtk_style_context_add_class(style_context, GTK_STYLE_CLASS_TOOLTIP );
320 
321 #if 0
322 GtkGrid {\
323     background-image: -gtk-gradient (linear, left top, right top, from (#aaa), to (#000));\
324     color: rgb(0,0,0);\
325     background-color: rgb(255,255,255);\
326     text-shadow: 1px 1px 0 white, -1px -1px 0 white, 1px -1px 0 white, -1px 1px 0 white, 2px 2px 0 white, 1px 2px 0 white, 2px 1px 0 white;\
327 }\
328 
329 #endif
330 
331     GtkCssProvider *css_provider = gtk_css_provider_new();
332     GError *error=NULL;
333     gtk_css_provider_load_from_data (css_provider,
334 "\
335 GtkEntry  {\
336     background-image: -gtk-gradient (linear, left top, right top, from (#888), to (#666));\
337     color: rgb(250,250,250);\
338     text-shadow: 0px 1px 0 black;\
339 }\
340 GtkBox,GtkEventBox,GtkFrame {\
341 background-image: -gtk-gradient (linear, left top, right top, from (#aaa), to (#000));\
342 color: rgb(255, 255, 255);\
343 border-width: 0px;\
344 border-radius: 0px;\
345 border-color: transparent;\
346 }\
347 ",
348         -1, &error);
349     if (error){
350         fprintf(stderr, "gerror: %s\n", error->message);
351         g_error_free(error);
352     }
353     gtk_style_context_add_provider (style_context, GTK_STYLE_PROVIDER(css_provider),
354                                 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
355 #endif
356     return;
357 }
358 
tooltip_placement_bug_workaround(GtkWidget * tooltip_window)359 static void tooltip_placement_bug_workaround(GtkWidget *tooltip_window){
360 #if GTK_MAJOR_VERSION==3
361 #if GTK_MINOR_VERSION>=8
362     // gtk3.8 bug workaround (still in current 3.13):
363     static gint last_x = 0;
364     static gint last_y = 0;
365 
366     GdkScreen *screen = gtk_widget_get_screen (tooltip_window);
367     gint monitor_num = gdk_screen_get_monitor_at_point (screen,
368                                                  last_x,
369                                                  last_y);
370     GdkRectangle monitor;
371     gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor);
372     last_x = monitor.width-1;
373     last_y = monitor.height-1;
374     gtk_window_move (GTK_WINDOW (tooltip_window),
375             last_x,last_y);
376 #endif
377 #endif
378         return;
379 }
380 
381 // If you just want the frame (as if to put in the properties dialog)
382 // call this function with widget set to NULL. Frame is what this function
383 // returns.
384 // If widget is not NULL, then the gtk tooltip  for the widget is set to the
385 // window created by this function.
386 GtkWidget *
rfm_create_tooltip_window(GtkWidget * widget,GtkWidget * tooltip_window,const GdkPixbuf * pixbuf,const gchar * markup,const gchar * label_text)387 rfm_create_tooltip_window(GtkWidget *widget, GtkWidget *tooltip_window, const GdkPixbuf *pixbuf, const gchar *markup, const gchar *label_text){
388     if (widget) {
389       gtk_widget_set_has_tooltip (widget, TRUE);
390       if (!tooltip_window) {
391         tooltip_window = gtk_window_new(GTK_WINDOW_POPUP);
392         NOOP(stderr, "New tooltip window now...\n");
393         g_signal_connect (G_OBJECT (tooltip_window), "map", G_CALLBACK (tooltip_map), NULL);
394         g_signal_connect (G_OBJECT (tooltip_window), "unmap", G_CALLBACK (tooltip_unmap), NULL);
395         gtk_window_set_type_hint (GTK_WINDOW (tooltip_window), GDK_WINDOW_TYPE_HINT_TOOLTIP);
396         gtk_widget_set_app_paintable (tooltip_window, TRUE);
397         gtk_window_set_resizable (GTK_WINDOW (tooltip_window), FALSE);
398         gtk_widget_set_name (tooltip_window, "gtk-tooltip");
399 
400 #if GTK_MAJOR_VERSION<3
401         GdkColor black = {0, 0, 0, 0};
402         gtk_widget_modify_bg(tooltip_window, GTK_STATE_NORMAL, &black);
403 #endif
404 
405       } else {
406         GtkWidget *old_content =
407             gtk_bin_get_child(GTK_BIN(tooltip_window));
408         gtk_container_remove(GTK_CONTAINER(tooltip_window), old_content);
409       }
410     }
411 
412     GtkWidget *vbox = rfm_vbox_new(FALSE, 2);
413     gtk_widget_show(vbox);
414 
415     if (widget){
416         GtkWidget *top_frame = gtk_frame_new(NULL);
417         gtk_widget_show(top_frame);
418 	gtk_container_add (GTK_CONTAINER (tooltip_window), top_frame);
419         gtk_container_add (GTK_CONTAINER (top_frame), vbox);
420     }
421 
422     GtkWidget *wbox  = gtk_event_box_new();
423     if (widget) {
424 #if GTK_MAJOR_VERSION<3
425     gint tip_bg = 0xf600;
426 	GdkColor whitish = {0, tip_bg, tip_bg, tip_bg};
427 	if (widget) gtk_widget_modify_bg(wbox, GTK_STATE_NORMAL, &whitish);
428 #endif
429     }
430     gtk_container_add (GTK_CONTAINER (vbox), wbox);
431     gtk_widget_show(wbox);
432 
433     GtkWidget *frame = gtk_frame_new(NULL);
434     gtk_widget_show(frame);
435     if (label_text) {
436 	GtkWidget *label = gtk_label_new("");
437 	gtk_widget_show(label);
438 	gchar *utf_text =  rfm_utf_string (label_text);
439 	gchar *label_markup;
440 	if (widget) {
441 #if GTK_MAJOR_VERSION<3
442 	    label_markup = g_strdup_printf("<span color=\"black\" font_family=\"monospace\" weight=\"bold\">%s</span>",utf_text);
443 #else
444 	    label_markup = g_strdup_printf("<span font_family=\"monospace\" weight=\"bold\">%s</span>",utf_text);
445 #endif
446 	} else {
447 #if GTK_MAJOR_VERSION<3
448 	    label_markup = g_strdup_printf("<span color=\"black\" font_family=\"monospace\" size=\"larger\" weight=\"bold\">%s</span>\n",utf_text);
449 #else
450 	    label_markup = g_strdup_printf("<span font_family=\"monospace\" size=\"larger\" weight=\"bold\">%s</span>\n",utf_text);
451 #endif
452 	}
453 	gtk_label_set_markup(GTK_LABEL(label), label_markup);
454 	g_free(utf_text);
455 	g_free(label_markup);
456 	gtk_frame_set_label_widget(GTK_FRAME(frame), label);
457     }
458     gtk_container_add (GTK_CONTAINER (wbox), frame);
459     gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_NONE);
460 
461     GtkWidget *box = rfm_hbox_new(FALSE, 2);
462     gtk_widget_show(box);
463     gtk_container_add (GTK_CONTAINER (frame), box);
464 
465     GtkWidget *tip_image = NULL;
466     if (pixbuf){
467 	if (label_text) {
468 	    GdkPixbuf *shadowed = shadow_it(pixbuf);
469 	    if (shadowed) {
470 		tip_image = gtk_image_new_from_pixbuf ((GdkPixbuf *)pixbuf);
471 		g_object_unref(shadowed);
472 	    } else {
473 		tip_image = gtk_image_new_from_pixbuf ((GdkPixbuf *)pixbuf);
474 	    }
475 	} else {
476 	    tip_image = gtk_image_new_from_pixbuf ((GdkPixbuf *)pixbuf);
477 	}
478 	gtk_box_pack_start(GTK_BOX(box),tip_image, FALSE, FALSE,0);
479 	gtk_widget_show(tip_image);
480     }
481     if (markup) {
482 	GtkWidget *label = gtk_label_new("");
483 	//gtk_widget_set_size_request (label, 60, -1);
484 	gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
485 	if (widget) {
486 //	    gchar *small = g_strdup_printf("<span color=\"white\" size=\"smaller\">%s</span>", markup);
487 #if GTK_MAJOR_VERSION<3
488 	    gchar *small = g_strdup_printf("<span color=\"black\" size=\"smaller\">%s</span>", markup);
489 	    //gchar *small = g_strdup_printf("<span background=\"white\" color=\"black\" size=\"smaller\">%s</span>", markup);
490 #else
491 	    gchar *small = g_strdup_printf("<span size=\"smaller\">%s</span>", markup);
492 #endif
493 	    gtk_label_set_markup(GTK_LABEL(label), small);
494 	    g_free(small);
495 
496 	} else {
497 	    gtk_label_set_markup(GTK_LABEL(label), markup);
498 	}
499 	gtk_box_pack_start(GTK_BOX(box),label,TRUE,TRUE,0);
500 	gtk_widget_show(label);
501     }
502 
503     gtk_widget_show(box);
504     if (widget) {
505 	g_object_set_data(G_OBJECT(tooltip_window), "box", box);
506 	g_object_set_data(G_OBJECT(tooltip_window), "image", tip_image);
507 	g_object_set_data(G_OBJECT(tooltip_window), "pixbuf", (void *)pixbuf);
508 	gint width = 0;
509 	gint height = 0;
510 	if (pixbuf) {
511 	    width = gdk_pixbuf_get_width(pixbuf);
512 	    height = gdk_pixbuf_get_height(pixbuf);
513 	}
514 	g_object_set_data(G_OBJECT(tooltip_window), "width", GINT_TO_POINTER(width));
515 	g_object_set_data(G_OBJECT(tooltip_window), "height", GINT_TO_POINTER(height));
516 
517 	gtk_widget_set_tooltip_window (widget, GTK_WINDOW(tooltip_window));
518 	gtk_widget_realize(tooltip_window);
519         rfm_set_box_gradient(wbox);
520         tooltip_placement_bug_workaround(tooltip_window);
521 	return tooltip_window;
522     }
523     rfm_set_box_gradient(wbox);
524     return vbox;
525 }
526 
527 static void
valid_widgets_unlock(void)528 valid_widgets_unlock(void){
529     rfm_view_list_unlock("valid_widgets_unlock");
530 }
531 
532 static gboolean
valid_widgets_lock(widgets_t * widgets_p)533 valid_widgets_lock(widgets_t *widgets_p){
534     if (!widgets_p) return FALSE;
535     rfm_global_t *rfm_global_p = rfm_global();
536     view_t *view_p = widgets_p->view_p;
537 
538     if (!view_p || !rfm_global_p || rfm_global_p->settings_widgets_p == widgets_p) {
539         rfm_view_list_lock(NULL, "valid_widgets_lock");
540         return TRUE;
541     }
542     if (rfm_view_list_lock(view_p, "valid_widgets_lock")) {
543         return TRUE;
544     }
545     return FALSE;
546 }
547 
548 static void *
get_visible_f(gpointer data)549 get_visible_f(gpointer data){
550     GtkWidget *widget=data;
551     if (GTK_IS_WIDGET(widget) && gtk_widget_get_visible(widget)) return GINT_TO_POINTER(1);
552     return NULL;
553 }
554 
555 gboolean
rfm_threaded_get_visible(GtkWidget * widget)556 rfm_threaded_get_visible(GtkWidget *widget){
557     if (g_thread_self() == rfm_get_gtk_thread()){
558         if (GTK_IS_WIDGET(widget)) return gtk_widget_get_visible(widget);
559     }
560     gboolean result =
561 	GPOINTER_TO_INT(rfm_context_function(get_visible_f, widget));
562     return result;
563 }
564 
565 
566 static void *
diagnostics_visible_f(gpointer data)567 diagnostics_visible_f(gpointer data){
568     widgets_t *widgets_p=data;
569     if (rfm_diagnostics_is_visible(widgets_p)) return GINT_TO_POINTER(1);
570     return NULL;
571 }
572 
573 gboolean
rfm_threaded_diagnostics_is_visible(widgets_t * widgets_p)574 rfm_threaded_diagnostics_is_visible(widgets_t *widgets_p){
575     rfm_global_t *rfm_global_p = rfm_global();
576     if (!rfm_global_p ){
577 	TRACE("rfm_threaded_diagnostics_is_visible: rfm_global_p==NULL\n");
578 	return FALSE;
579     }
580     if (g_thread_self() == rfm_get_gtk_thread()){
581 	return rfm_diagnostics_is_visible(widgets_p);
582     }
583     gboolean result =
584 	GPOINTER_TO_INT(rfm_context_function(diagnostics_visible_f, widgets_p));
585     return result;
586 }
587 
588 
589 typedef struct sequence_t {
590     const gchar *id;
591     const gchar *sequence;
592 } sequence_t;
593 
594 
595 static sequence_t sequence_v[] = {
596         {"xffm_tag/black", "30"},
597         {"xffm_tag/black_bg", "40"},
598         {"xffm_tag/red", "31"},
599         {"xffm_tag/red_bg", "41"},
600         {"xffm_tag/green", "32"},
601         {"xffm_tag/green_bg", "42"},
602         {"xffm_tag/yellow", "33"},
603         {"xffm_tag/yellow_bg", "43"},
604         {"xffm_tag/blue", "34"},
605         {"xffm_tag/blue_bg", "44"},
606         {"xffm_tag/magenta", "35"},
607         {"xffm_tag/magenta_bg", "45"},
608         {"xffm_tag/cyan", "36"},
609         {"xffm_tag/cyan_bg", "46"},
610         {"xffm_tag/white", "37"},
611         {"xffm_tag/white_bg", "47"},
612 
613         {"xffm_tag/bold", "1"},
614         {"xffm_tag/bold", "01"},
615         {"xffm_tag/italic", "4"},
616         {"xffm_tag/italic", "04"},
617         {"xffm_tag/blink", "5"},
618         {"xffm_tag/blink", "05"},
619         {NULL, ""},
620         {NULL, "0"},
621         {NULL, "00"},
622         {NULL, "22"},
623         {NULL, "24"},
624         {NULL, NULL}            // this marks the end of sequences.
625 };
626 
627 
628 static const gchar *
get_xffm_ansi_tag(const gchar * code)629 get_xffm_ansi_tag(const gchar *code){
630     sequence_t *p;
631     for(p = sequence_v; p && p->sequence; p++) {
632 	if(strcmp (code, p->sequence) == 0) {
633 	    return p->id;
634 	}
635     }
636     return NULL;
637 
638 }
639 
640 #if 0
641 static sequence_t sequence_p[] = {
642         {"xffm_tag/black", "[01;30m"},
643         {"xffm_tag/black", "[30m"},
644         {"xffm_tag/red", "[31m"},
645         {"xffm_tag/red", "[01;31m"},
646         {"xffm_tag/red", "[31;01m"},
647         {"xffm_tag/green", "[32m"},
648         {"xffm_tag/green", "[01;32m"},
649         {"xffm_tag/green", "[32;01m"},
650         {"xffm_tag/yellow", "[33m"},
651         {"xffm_tag/yellow", "[01;33m"},
652         {"xffm_tag/yellow", "[33;01m"},
653         {"xffm_tag/blue", "[34m"},
654         {"xffm_tag/blue", "[01;34m"},
655         {"xffm_tag/blue", "[34;01m"},
656         {"xffm_tag/magenta", "[35m"},
657         {"xffm_tag/magenta", "[01;35m"},
658         {"xffm_tag/magenta", "[35;01m"},
659         {"xffm_tag/cyan", "[36m"},
660         {"xffm_tag/cyan", "[01;36m"},
661         {"xffm_tag/cyan", "[36;01m"},
662         {"xffm_tag/white", "[37m"},
663         {"xffm_tag/white", "[01;37m"},
664         {"xffm_tag/white", "[37;01m"},
665 
666         {"xffm_tag/bold", "[1m"},
667         {"xffm_tag/bold", "[01m"},
668         {"xffm_tag/italic", "[4m"},
669         {"xffm_tag/italic", "[04m"},
670         {"xffm_tag/italic", "[4;1m"},
671         {"xffm_tag/italic", "[04;01m"},
672         {NULL, "[m"},
673         {NULL, "[0m"},
674         {NULL, "[22m"},
675         {NULL, "[24m"},
676         {NULL, NULL}            // this marks the end of sequences.
677 };
678 #endif
679 
680 // This is to output colors to stdout.
681 const gchar *
rfm_lp_color(enum color_e color)682 rfm_lp_color(enum color_e color){
683     switch (color){
684 	case RED: return "[31m";
685 	case GREEN: return "[32m";
686 	case BLUE: return "[34m";
687 	case YELLOW: return "[33m";
688 	case MAGENTA: return "[35m";
689 	case CYAN: return "[36m";
690 	case WHITE: return "[37m";
691 	case BLACK: return "[30m";
692 	case BOLD: return "[1m";
693 	case ITALIC: return "[4m";
694     }
695     return NULL;
696 }
697 
698 void
rfm_set_store_data_from_list(GtkListStore * list_store,GSList ** list)699 rfm_set_store_data_from_list(GtkListStore *list_store, GSList **list){
700     GtkTreeIter iter;
701     gtk_list_store_clear (list_store);
702     GSList *p = *list;
703     for (; p && p->data; p=p->next) {
704 	gtk_list_store_append (list_store, &iter);
705 	gtk_list_store_set (list_store, &iter,
706                           0, (gchar *)p->data,
707                           -1);
708       /* Note: The store will keep a copy of the string internally,
709        * so the list may be freed */
710     }
711 }
712 
713 
714 static gboolean
little_button_press(GtkWidget * button,GdkEventButton * event,gpointer callback_data)715 little_button_press (GtkWidget *button, GdkEventButton  *event, gpointer callback_data){
716 	    TRACE( "little button press %d...\n", event->button);
717     g_object_set_data(G_OBJECT(button), "button_id", GUINT_TO_POINTER(event->button));
718     if (event->button != 3) return FALSE;
719     void (*button_callback)(GtkButton * button, gpointer data);
720     button_callback = g_object_get_data(G_OBJECT(button), "callback");
721     // popit with callback data.
722     if (button_callback){
723 	    TRACE( "popit with callback data...\n");
724 	(*button_callback)(GTK_BUTTON(button), callback_data);
725     }
726     return FALSE;
727 }
728 
729 
730 static GtkWidget *tt_window = NULL;
731 
732 void
rfm_reset_tooltip(GtkWidget * widget)733 rfm_reset_tooltip(GtkWidget * widget){
734     NOOP(stderr, "rfm_reset_tooltip\n");
735     if (tt_window) {
736 	g_object_set_data(G_OBJECT(tt_window), "tooltip_target", NULL);
737 	NOOP(stderr, "rfm_reset_tooltip OK\n");
738     }
739 }
740 
741 // FIXME: on view destroy, all tooltip texts associated to widgets (button mainly)
742 //        should be freed and removed from hashtable. (small leak here)
743 static GHashTable *tooltip_text_hash = NULL;
744 
745 static gboolean
widget_tooltip_function(GtkWidget * widget,gint x,gint y,gboolean keyboard_mode,GtkTooltip * tooltip,gpointer user_data)746 widget_tooltip_function(
747         GtkWidget * widget,
748         gint x,
749         gint y,
750         gboolean keyboard_mode,
751         GtkTooltip * tooltip,
752         gpointer user_data
753 ) {
754     if (tt_window) {
755 	GtkWidget *tooltip_target =
756 	    g_object_get_data(G_OBJECT(tt_window), "tooltip_target");
757 	if (tooltip_target == widget) return TRUE;
758     }
759 
760     GdkPixbuf *tooltip_pixbuf = g_object_get_data(G_OBJECT(widget), "tooltip_pixbuf");
761     gchar *tooltip_text = g_object_get_data(G_OBJECT(widget), "tooltip_text");
762     gchar *label_text = NULL;
763 
764     NOOP(stderr, "New tooltip \"%s\"\n", tooltip_text);
765     if (tooltip_text){
766 	if (strchr(tooltip_text, '\n')) {
767 	    label_text = g_strdup(tooltip_text);
768 	    *(strchr(label_text, '\n')) = 0;
769 	    tooltip_text = strchr(tooltip_text, '\n') + 1;
770 	}
771     }
772     tt_window = rfm_create_tooltip_window(widget, tt_window, tooltip_pixbuf, tooltip_text, label_text);
773 
774     g_object_set_data(G_OBJECT(tt_window), "tooltip_target", widget);
775 
776     g_free(label_text);
777     return TRUE;
778 }
779 
780 static void
destroy_widget(GtkWidget * button,void * data)781 destroy_widget(GtkWidget *button, void *data){
782     GdkPixbuf *tooltip_pixbuf = g_object_get_data(G_OBJECT(button), "tooltip_pixbuf");
783     gchar *tooltip_text = g_hash_table_lookup(tooltip_text_hash, button);
784 //        g_object_get_data(G_OBJECT(button), "tooltip_text");
785     if (tooltip_text) {
786         // The free is done by removing item from hash table:
787         // g_free(tooltip_text);
788         g_hash_table_remove(tooltip_text_hash, button);
789     }
790 
791     if (tooltip_pixbuf) g_object_unref(tooltip_pixbuf);
792     g_object_set_data(G_OBJECT(button), "tooltip_text", NULL);
793     g_object_set_data(G_OBJECT(button), "tooltip_pixbuf", NULL);
794 }
795 
796 static void *
custom_tooltip_f(gpointer data)797 custom_tooltip_f(gpointer data){
798     void **arg=data;
799     GtkWidget *widget = arg[0];
800     GdkPixbuf *pixbuf = arg[1];
801     const gchar *text = arg[2];
802     if (!tooltip_text_hash) {
803         tooltip_text_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free);
804     }
805     gchar *t = g_strdup(text);
806     g_object_set_data(G_OBJECT(widget), "tooltip_text", t);
807     g_hash_table_replace(tooltip_text_hash, widget, t);
808     g_object_set_data(G_OBJECT(widget), "tooltip_pixbuf", pixbuf);
809     if (pixbuf) g_object_ref(pixbuf);
810 
811     gtk_widget_set_has_tooltip(widget, TRUE);
812     g_signal_connect (G_OBJECT (widget), "destroy",
813 	    G_CALLBACK (destroy_widget), NULL);
814     g_signal_connect (G_OBJECT (widget), "query-tooltip",
815 	    G_CALLBACK (widget_tooltip_function), widget);
816     return NULL;
817 }
818 
rfm_add_custom_tooltip(GtkWidget * widget,GdkPixbuf * pixbuf,const gchar * text)819 void rfm_add_custom_tooltip(GtkWidget *widget, GdkPixbuf *pixbuf, const gchar *text){
820     //rfm_global_t *rfm_global_p = rfm_global();
821     void *arg[]={widget, pixbuf, (void *)text};
822 
823     if (rfm_get_gtk_thread() == g_thread_self()) custom_tooltip_f(arg);
824     rfm_context_function(custom_tooltip_f, arg);
825 }
826 
827 GtkWidget *
rfm_mk_little_button(const gchar * icon_id,void * callback,void * callback_data,const gchar * tooltip_text)828 rfm_mk_little_button (const gchar * icon_id, void *callback, void *callback_data, const gchar * tooltip_text) {
829     GtkWidget *button;
830     button = gtk_button_new ();
831     gtk_widget_set_can_focus (button, FALSE);
832 
833     gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
834     GdkPixbuf *pb = NULL;
835     if(icon_id) {
836         GtkWidget *image;
837         pb = rfm_get_pixbuf (icon_id, SIZE_BUTTON);
838         image = gtk_image_new_from_pixbuf (pb);
839 	g_object_unref(pb);
840         gtk_widget_show (image);
841         gtk_container_add (GTK_CONTAINER (button), image);
842     }
843     if(tooltip_text && strlen (tooltip_text)) {
844         rfm_add_custom_tooltip(button, pb, tooltip_text);
845     }
846     if(callback) {
847         NOOP ("DIAGNOSTICS: run button connected to callback\n");
848 	g_object_set_data(G_OBJECT(button), "callback", callback);
849         g_signal_connect ((gpointer) button, "button-press-event", G_CALLBACK (little_button_press), callback_data);
850         g_signal_connect ((gpointer) button, "clicked", G_CALLBACK (callback), callback_data);
851     }
852     return button;
853 }
854 
855 void *
rfm_cursor_wait(gpointer data)856 rfm_cursor_wait (gpointer data) {
857     GtkWidget * widget = data;
858     static GdkCursor *cursor = NULL;
859     if(!widget) return NULL;
860     if(!cursor) cursor = gdk_cursor_new_for_display (gdk_display_get_default(),GDK_WATCH);
861     gdk_window_set_cursor (gtk_widget_get_window(widget), cursor);
862     return NULL;
863 }
864 
865 
866 void *
rfm_cursor_reset(gpointer data)867 rfm_cursor_reset (gpointer data) {
868     GtkWidget * widget = data;
869     if(!widget) return NULL;
870     gdk_window_set_cursor (gtk_widget_get_window(widget), NULL);
871     return NULL;
872 }
873 
874 
875 
876 static void
clear_diagnostics_window(GtkButton * button,gpointer data)877 clear_diagnostics_window (GtkButton * button, gpointer data) {
878     widgets_t *widgets_p = data;
879     NOOP ("clear_diagnostics_window() now \n");
880     if (widgets_p->diagnostics_window==NULL) {
881 	g_error("widgets_p->diagnostics_window==NULL");
882     }
883     rfm_clear_text (widgets_p);
884     return;
885 }
886 
887 #define ICONOFY_BUTTON 1
888 #ifdef ICONOFY_BUTTON
889 // This function is necessary because fvwm does not put in a minimize
890 // button for child windows of the desktop window. Actually, no decorations
891 // are used for any child windows of the desktop window.
892 static void
iconofy_diagnostics_window(GtkButton * button,gpointer data)893 iconofy_diagnostics_window (GtkButton * button, gpointer data) {
894     widgets_t *widgets_p = data;
895     if (widgets_p->diagnostics_window==NULL) g_error("widgets_p->diagnostics_window==NULL");
896     gtk_window_iconify(GTK_WINDOW(widgets_p->diagnostics_window));
897     return;
898 }
899 #endif
900 
901 
902 static gboolean
destroy_diagnostics_window(GtkWidget * widget,GdkEvent * event,gpointer data)903 destroy_diagnostics_window (GtkWidget * widget, GdkEvent * event, gpointer data) {
904     //return TRUE;
905     // Just hide it.
906     widgets_t *widgets_p = data;
907     NOOP ("destroy_diagnostics_window() now \n");
908     if (widgets_p->diagnostics_window==NULL)  return TRUE;
909     gtk_window_iconify(GTK_WINDOW((widgets_p->diagnostics_window)));
910     // Hiding does not work right since if input is flowing to
911     // the widget, GTK gets confused and will not show it again
912     // (at least with fvwm).
913     //gtk_widget_hide((widgets_p->diagnostics_window));
914     // Let's try simply setting the configuration option to hide it...
915     rfm_rational (RFM_MODULE_DIR, "settings", (void *)"RFM_ENABLE_DESKTOP_DIAGNOSTICS", (void *)"", "mcs_set_var");
916 
917     return TRUE;
918 }
919 
920 static void
close_diagnostics_window(GtkWidget * widget,gpointer data)921 close_diagnostics_window (GtkWidget * widget, gpointer data) {
922     destroy_diagnostics_window (NULL, NULL, data);
923 }
924 
925 GtkWidget *
rfm_create_diagnostics_window(widgets_t * widgets_p)926 rfm_create_diagnostics_window (widgets_t * widgets_p) {
927     if (widgets_p->diagnostics_window != NULL) {
928 	DBG("rfm_create_diagnostics_window(): diagnostics_window already exists.\n");
929 	return (widgets_p->diagnostics_window);
930     }
931     GtkWidget *dialog,
932      *button,
933      *scrolledwindow,
934      *hbox;
935     //dialog = gtk_dialog_new ();
936     //// THis instead:
937     dialog = gtk_window_new (GTK_WINDOW_TOPLEVEL);
938     gtk_window_set_keep_above (GTK_WINDOW(dialog), TRUE);
939     gtk_window_set_type_hint(GTK_WINDOW(dialog), GDK_WINDOW_TYPE_HINT_DIALOG);
940 
941 
942     gtk_window_stick (GTK_WINDOW(dialog));
943 
944 
945     (widgets_p->diagnostics_window) = dialog;
946 
947 
948 
949     g_object_set_data(G_OBJECT(dialog), "widgets_p", widgets_p);
950     gchar *title=g_strdup(_("Console Message Viewer"));
951     gtk_window_set_title (GTK_WINDOW (dialog), title);
952     GdkPixbuf *pixbuf = rfm_get_pixbuf("xffm/emblem_terminal", SIZE_ICON);
953     gtk_window_set_icon (GTK_WINDOW (dialog), pixbuf);
954     g_object_unref(pixbuf);
955     g_free(title);
956     gtk_window_set_resizable (GTK_WINDOW (dialog), TRUE);
957     gtk_container_set_border_width (GTK_CONTAINER (dialog), 6);
958 
959     /* create diagnostics textview */
960     widgets_p->diagnostics = gtk_text_view_new ();
961     scrolledwindow = gtk_scrolled_window_new (NULL, NULL);
962     gtk_widget_set_size_request (scrolledwindow, 600, 400);
963 
964     gtk_container_add (GTK_CONTAINER (scrolledwindow), (widgets_p->diagnostics));
965     gtk_container_set_border_width (GTK_CONTAINER ((widgets_p->diagnostics)), 2);
966 
967     gtk_widget_set_can_focus ((widgets_p->diagnostics), FALSE);
968     gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW ((widgets_p->diagnostics)), GTK_WRAP_WORD);
969     gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW ((widgets_p->diagnostics)), FALSE);
970 
971 #if 0
972     oobbsoolete. just check if needed for desktop console with gtk2 (probably not)
973 #if GTK_MAJOR_VERSION==2
974     	gint size = 10; //8 This only for desktop....
975         PangoFontDescription *font_desc = pango_font_description_new ();
976         pango_font_description_set_family (font_desc, "monospace");
977         pango_font_description_set_size (font_desc, size * PANGO_SCALE);
978 	gtk_widget_modify_font ((widgets_p->diagnostics), font_desc);
979 	pango_font_description_free (font_desc);
980 #endif
981 
982 #if GTK_MAJOR_VERSION==3
983         // GTK_MINOR_VERSION>=15 is taken care of with style below.
984     	gint size = 10; //8 This only works for desktop....
985         PangoFontDescription *font_desc = pango_font_description_new ();
986         pango_font_description_set_family (font_desc, "monospace");
987         pango_font_description_set_size (font_desc, size * PANGO_SCALE);
988         gtk_widget_override_font ((widgets_p->diagnostics), font_desc);
989 	pango_font_description_free (font_desc);
990 #endif
991 #endif
992 
993     GtkWidget *vbox = rfm_vbox_new (FALSE, 0);
994     gtk_widget_show (vbox);
995     gtk_container_add (GTK_CONTAINER (dialog), vbox);
996 
997     gtk_box_pack_start (GTK_BOX (vbox), scrolledwindow, TRUE, TRUE, 0);
998 
999     hbox = rfm_hbox_new (FALSE, 0);
1000 
1001     gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
1002 
1003     button = rfm_dialog_button ("xffm/stock_close", _("Close"));
1004     gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
1005     g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (close_diagnostics_window), widgets_p);
1006 
1007     button = rfm_dialog_button ("xffm/stock_clear", _("Clear"));
1008     gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
1009     g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (clear_diagnostics_window), widgets_p);
1010 
1011 #ifdef ICONOFY_BUTTON
1012     button = rfm_dialog_button ("xffm/stock_go-bottom", _("Iconify"));
1013     gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
1014     g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (iconofy_diagnostics_window), widgets_p);
1015 #endif
1016 
1017 
1018     g_signal_connect (G_OBJECT (dialog), "destroy_event", G_CALLBACK (destroy_diagnostics_window), widgets_p);
1019     g_signal_connect (G_OBJECT (dialog), "delete_event", G_CALLBACK (destroy_diagnostics_window), widgets_p);
1020 
1021     widgets_p->button_space = rfm_hbox_new (FALSE, 0);
1022     gtk_box_pack_start (GTK_BOX (hbox), widgets_p->button_space, FALSE, FALSE, 0);
1023     gtk_widget_realize (dialog);
1024 
1025     if(!getenv ("RFM_ENABLE_DESKTOP_DIAGNOSTICS") ||
1026 	  strlen (getenv ("RFM_ENABLE_DESKTOP_DIAGNOSTICS"))==0)
1027     {
1028 	gtk_widget_hide (dialog);
1029     } else {
1030         gtk_window_iconify(GTK_WINDOW((widgets_p->diagnostics_window)));
1031 	gtk_widget_show_all (dialog);
1032     }
1033 
1034     return dialog;
1035 
1036 }
1037 
1038 void
rfm_update_status_line(view_t * view_p)1039 rfm_update_status_line (view_t * view_p) {
1040     if(!view_p->widgets.status) return;
1041     // Deactivate lpinput...
1042     g_object_set_data (G_OBJECT (view_p->widgets.status), "active", NULL);
1043     // Item selected:
1044     if(view_p->selection_list && g_slist_length (view_p->selection_list) == 1) {
1045         record_entry_t *en = view_p->selection_list->data;
1046         if(en && en->path) {
1047             GError *error = NULL;
1048             const gchar *id = "xffm/stock_file";
1049 	    if (en && IS_SDIR(en->type)){
1050 		if (IS_LOCAL_TYPE(en->type)) id = "xffm/stock_directory";
1051 		else id ="xffm/emblem_shared";
1052 	    } else if (en && en->mimetype) id = en->mimetype;
1053             gchar *g = g_path_get_basename (en->path);
1054             gchar *gg = g_locale_to_utf8 (g, -1, NULL, NULL, &error);
1055             if(gg){
1056                 rfm_threaded_status (&(view_p->widgets), id, g_strconcat(gg, NULL));
1057 	    }
1058             else {
1059                 DBG ("g_locale_to_utf8(%s): %s\n", g, error->message);
1060                 g_error_free (error);
1061             }
1062             g_free (g);
1063             g_free (gg);
1064         }
1065     }
1066     // Items selected:
1067     else if(view_p->selection_list && g_slist_length (view_p->selection_list) >= 1) {
1068         gchar *g=
1069             g_strdup_printf (ngettext ("%'d item selected", "%'d items selected",
1070                 g_slist_length (view_p->selection_list)),
1071                     g_slist_length (view_p->selection_list));
1072         rfm_threaded_status (&(view_p->widgets), "xffm/stock_info", g);
1073     }
1074     // Use en->tag for status line.
1075     else {
1076         const gchar *icon = "xffm/emblem_symbolic-link";
1077         if(view_p->en){
1078 	    if (view_p->en->module){
1079 		const gchar *m_icon = rfm_void(PLUGIN_DIR, view_p->en->module,
1080 			"module_icon_id");
1081 		if (m_icon) icon = m_icon;
1082 
1083 	    }
1084 	    if (view_p->en->tag == NULL) {
1085 		gint items=0;
1086 		for (;view_p->population_pp && view_p->population_pp[items]; items++);
1087 		if (IS_SDIR(view_p->en->type)){
1088 		    if (IS_LOCAL_TYPE(view_p->en->type)) {
1089 			icon = "xffm/stock_directory";
1090 		    } else icon ="xffm/emblem_shared";
1091 		}
1092 		gchar *g = g_strdup_printf (ngettext (" (containing %'d item)", " (containing %'d items)", items), items);
1093 		gchar *b = g_path_get_basename(view_p->en->path);
1094 		view_p->en->tag = g_strdup_printf ("%s %s", b, g);
1095 		g_free(b);
1096 		g_free(g);
1097 	    }
1098 	    rfm_threaded_status (&(view_p->widgets), icon,  g_strdup(view_p->en->tag));
1099 	}
1100     }
1101 
1102 }
1103 
1104 
1105 #if GTK_MAJOR_VERSION==3
1106 //&& GTK_MINOR_VERSION>=4
1107 typedef struct lpterm_colors_t {
1108     const gchar *id;
1109     GdkRGBA color;
1110 } lpterm_colors_t;
1111 static
1112 GtkTextTag *
resolve_tag(GtkTextBuffer * buffer,const gchar * id)1113 resolve_tag (GtkTextBuffer * buffer, const gchar * id) {
1114     GtkTextTag *tag = NULL;
1115     lpterm_colors_t lpterm_colors_v[] = {
1116         {"xffm_tag/command",
1117          { 0.3451, 0x3434, 0.8118, 1.0}},
1118         {"xffm_tag/stderr",
1119          { 0.8, 0, 0, 1.0}},
1120         {"xffm_tag/command_id",
1121          { 0.0, 0.0, 1.0, 1.0}},
1122 
1123        {"xffm_tag/green",
1124          { 0.0, 0.8039, 0.0, 1.0}},
1125         {"xffm_tag/red",
1126          { 0.8039, 0.0, 0.0, 1.0}},
1127         {"xffm_tag/blue",
1128          { 0.0, 0.0, 0.8039, 1.0}},
1129         {"xffm_tag/yellow",
1130          { 0.8039, 0.8039, 0.0, 1.0}},
1131         {"xffm_tag/magenta",
1132          { 0.8039, 0.0, 0.8039, 1.0}},
1133         {"xffm_tag/cyan",
1134          { 0.0, 0.8039, 0.8039, 1.0}},
1135 
1136         {"xffm_tag/black",
1137          { 0.0, 0.0, 0.0, 1.0}},
1138         {"xffm_tag/white",
1139          { 1.0, 1.0, 1.0, 1.0}},
1140 
1141         {"xffm_tag/grey",
1142          { 0x8888, 0x8888, 0x8888}},
1143         {NULL,
1144          { 0.0, 0.0, 0.0}}
1145 
1146     };
1147     void *initialized = g_object_get_data(G_OBJECT(buffer), "text_tag_initialized");
1148     if (!initialized) {
1149 	lpterm_colors_t *p = lpterm_colors_v;
1150         for(; p && p->id; p++) {
1151 	    gtk_text_buffer_create_tag (buffer, p->id,
1152 		    "foreground-rgba", &(p->color),
1153 		    NULL);
1154 	    gchar *bg_id = g_strconcat(p->id, "_bg", NULL);
1155  	    gtk_text_buffer_create_tag (buffer, bg_id,
1156 		    "background-rgba", &(p->color),
1157 		    NULL);
1158 	    g_free(bg_id);
1159        }
1160         // XXX Weight and style are not colors. This is not quite right...
1161         gtk_text_buffer_create_tag (buffer, "xffm/bold", "weight", PANGO_WEIGHT_BOLD, "foreground-rgba", NULL, NULL);
1162         gtk_text_buffer_create_tag (buffer, "xffm/italic", "style", PANGO_STYLE_ITALIC, "foreground-rgba", NULL, NULL);
1163 	g_object_set_data(G_OBJECT(buffer), "text_tag_initialized", GINT_TO_POINTER(1));
1164     }
1165 
1166     if (!id) return NULL;
1167     tag = gtk_text_tag_table_lookup (gtk_text_buffer_get_tag_table (buffer), id);
1168     if (!tag) NOOP(stderr, "No GtkTextTag for %s\n", id);
1169     return tag;
1170 }
1171 
1172 #else
1173 typedef struct lpterm_colors_t {
1174     const gchar *id;
1175     GdkColor color;
1176 } lpterm_colors_t;
1177 static
1178 GtkTextTag *
resolve_tag(GtkTextBuffer * buffer,const gchar * id)1179 resolve_tag (GtkTextBuffer * buffer, const gchar * id) {
1180 
1181     GtkTextTag *tag = NULL;
1182     lpterm_colors_t lpterm_colors_v[] = {
1183         {"xffm_tag/command",
1184          {101, 0x5858, 0x3434, 0xcfcf}},
1185         {"xffm_tag/stderr",
1186          {102, 0xcccc, 0, 0}},
1187         {"xffm_tag/command_id",
1188          {103, 0x0000, 0x0000, 0xffff}},
1189 
1190        {"xffm_tag/green",
1191          {104, 0x0000, 0xcdcd, 0x0000}},
1192         {"xffm_tag/red",
1193          {105, 0xcdcd, 0x0000, 0x0000}},
1194         {"xffm_tag/blue",
1195          {106, 0x0000, 0x0000, 0xcdcd}},
1196         {"xffm_tag/yellow",
1197          {107, 0xcdcd, 0xcdcd, 0x0000}},
1198         {"xffm_tag/magenta",
1199          {108, 0xcdcd, 0x0000, 0xcdcd}},
1200         {"xffm_tag/cyan",
1201          {109, 0x0000, 0xcdcd, 0xcdcd}},
1202 
1203         {"xffm_tag/black",
1204          {1, 0x0000, 0x0000, 0x0000}},
1205         {"xffm_tag/white",
1206          {0, 0xffff, 0xffff, 0xffff}},
1207 
1208         {"xffm_tag/grey",
1209          {110, 0x8888, 0x8888, 0x8888}},
1210         {NULL,
1211          {0, 0, 0, 0}}
1212 
1213     };
1214     void *initialized = g_object_get_data(G_OBJECT(buffer), "text_tag_initialized");
1215     if (!initialized) {
1216 	lpterm_colors_t *p = lpterm_colors_v;
1217         for(; p && p->id; p++) {
1218 	    gtk_text_buffer_create_tag (buffer, p->id,
1219 		    "foreground_gdk", &(p->color),
1220 		    NULL);
1221 	    gchar *bg_id = g_strconcat(p->id, "_bg", NULL);
1222  	    gtk_text_buffer_create_tag (buffer, bg_id,
1223 		    "background_gdk", &(p->color),
1224 		    NULL);
1225 	    g_free(bg_id);
1226        }
1227         gtk_text_buffer_create_tag (buffer, "xffm/bold", "weight", PANGO_WEIGHT_BOLD, "foreground_gdk", NULL, NULL);
1228         gtk_text_buffer_create_tag (buffer, "xffm/italic", "style", PANGO_STYLE_ITALIC, "foreground_gdk", NULL, NULL);
1229 	g_object_set_data(G_OBJECT(buffer), "text_tag_initialized", GINT_TO_POINTER(1));
1230     }
1231 
1232     if (!id) return NULL;
1233     tag = gtk_text_tag_table_lookup (gtk_text_buffer_get_tag_table (buffer), id);
1234     if (!tag) NOOP(stderr, "No GtkTextTag for %s\n", id);
1235     return tag;
1236 }
1237 #endif
1238 
1239 void
rfm_clear_sh_command_history(view_t * view_p,gboolean disk_too)1240 rfm_clear_sh_command_history (view_t * view_p, gboolean disk_too) {
1241     if(disk_too) {
1242         gchar *history = g_build_filename ( LP_TERMINAL_HISTORY, NULL);
1243         unlink (history);
1244     }
1245     GList *p;
1246     for(p = g_list_first (view_p->sh_command); p && p->data; p = p->next) {
1247         g_free (p->data);
1248     }
1249     g_list_free (view_p->sh_command);
1250     view_p->sh_command = NULL;
1251     view_p->sh_command_counter = 0;
1252 }
1253 
1254 
1255 // thread function (null)
1256 void
rfm_dump_output(void * user_data,void * stream,int childFD)1257 rfm_dump_output (void *user_data, void *stream, int childFD) {
1258     return;
1259 }
1260 
1261 static void *
threaded_status_f(gpointer data)1262 threaded_status_f(gpointer data){
1263     void **arg = data;
1264     widgets_t *widgets_p = arg[0];
1265     gchar *icon = arg[1];
1266     gchar *string = arg[2];
1267 
1268     if (valid_widgets_lock(widgets_p)) {
1269 	rfm_status (widgets_p, icon, string, NULL);
1270         valid_widgets_unlock();
1271     }
1272     g_free(icon);
1273     g_free(string);
1274     g_free(arg);
1275     return NULL;
1276 }
1277 
1278 static void *
threaded_diagnostics_f(gpointer data)1279 threaded_diagnostics_f(gpointer data){
1280     void **arg = data;
1281     widgets_t *widgets_p = arg[0];
1282     gchar *icon = arg[1];
1283     gchar *string = arg[2];
1284 
1285     if (valid_widgets_lock(widgets_p)) {
1286         rfm_diagnostics (widgets_p, icon, string, NULL);
1287         valid_widgets_unlock();
1288     }
1289 
1290     g_free(icon);
1291     g_free(string);
1292     return NULL;
1293 }
1294 
1295 void
rfm_threaded_status(widgets_t * widgets_p,const gchar * icon,gchar * string)1296 rfm_threaded_status(widgets_t *widgets_p, const gchar *icon, gchar *string){
1297     void **arg = (void **) malloc(3*sizeof(void*));
1298     if (!arg) g_error("malloc: %s\n", strerror(errno));
1299     arg[0] = widgets_p;
1300     arg[1] = g_strdup(icon);
1301     arg[2] = string;
1302     rfm_context_function(threaded_status_f, arg);
1303     return;
1304 }
1305 
1306 void
rfm_threaded_diagnostics(widgets_t * widgets_p,const gchar * icon,gchar * string)1307 rfm_threaded_diagnostics(widgets_t *widgets_p, const gchar *icon, gchar *string){
1308     static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
1309 
1310     if (g_thread_self() == rfm_get_gtk_thread()){
1311         rfm_diagnostics(widgets_p, icon, string, NULL);
1312         g_free(string);
1313 	return ;
1314     }
1315     if (string && strchr(string, 0x0d)){
1316         *strchr(string, 0x0d) = ' ';// ^M
1317     }
1318 
1319 
1320     pthread_mutex_lock(&mutex);
1321     void *arg[3];
1322     arg[0] = widgets_p;
1323     arg[1] = g_strdup(icon);
1324     arg[2] = string;
1325     rfm_context_function(threaded_diagnostics_f, arg);
1326     pthread_mutex_unlock(&mutex);
1327     return;
1328 }
1329 
1330 // This is a thread function, must have GDK mutex set for gtk commands...
1331 void
rfm_operate_stderr(void * user_data,void * stream,int childFD)1332 rfm_operate_stderr (void *user_data, void *stream, int childFD) {
1333     widgets_t *widgets_p = user_data;
1334     rfm_global_t *rfm_global_p = rfm_global();
1335     if (rfm_global_p){
1336 	g_mutex_lock(rfm_global_p->status_mutex);
1337 	gint status = rfm_global_p->status;
1338 	g_mutex_unlock(rfm_global_p->status_mutex);
1339 	if (status == STATUS_EXIT) return;
1340     }
1341     view_t *view_p = NULL;
1342     if (widgets_p) view_p = widgets_p->view_p;
1343     if (view_p){
1344 	g_mutex_lock(view_p->mutexes.status_mutex);
1345 	gboolean status = view_p->flags.status;
1346 	g_mutex_unlock(view_p->mutexes.status_mutex);
1347 	if (status == STATUS_EXIT) return;
1348     }
1349     char *line;
1350     line = (char *)stream;
1351 
1352 
1353     if(line[0] != '\n') {
1354 	// Is the view still valid (valid_view?)
1355         TRACE("rfm_operate_stderr()...\n");
1356         if (!rfm_view_list_lock(view_p, "rfm_operate_stderr")) return;
1357 	if (widgets_p) {
1358 	    rfm_threaded_diagnostics(widgets_p, "xffm_tag/stderr", g_strdup(line));
1359 	} else {
1360             TRACE( "%s", line);
1361         }
1362         rfm_view_list_unlock("rfm_operate_stderr");
1363     }
1364     // This is a bit hacky, to keep runaway output from hogging
1365     // up the gtk event loop.
1366     static gint count = 1;
1367     if (count % 20 == 0){
1368         usleep(100000);
1369     } else {
1370         usleep(1000);
1371     }
1372 
1373    return;
1374 }
1375 
1376 // This will hash commands to know what has just finished
1377 // Too useful to just be in debug mode
1378 #if 1
1379 //#ifdef DEBUG
1380 static GHashTable *c_string_hash=NULL;
1381 pthread_mutex_t string_hash_mutex = PTHREAD_MUTEX_INITIALIZER;
1382 
1383 static
pop_hash(pid_t controller)1384 gchar *pop_hash(pid_t controller){
1385     if (!c_string_hash) {
1386         DBG("Popping empty hash\n");
1387         return g_strdup("");
1388     }
1389     pthread_mutex_lock(&string_hash_mutex);
1390     gchar *string = g_hash_table_lookup (c_string_hash, GINT_TO_POINTER(controller));
1391     if (!string){
1392         pthread_mutex_unlock(&string_hash_mutex);
1393         DBG("controller %d not found in hashtable\n", controller);
1394         return g_strdup("");
1395     }
1396     g_hash_table_steal(c_string_hash, GINT_TO_POINTER(controller));
1397     pthread_mutex_unlock(&string_hash_mutex);
1398     gchar bold[]={27, '[', '1', 'm',0};
1399     gchar *dbg_string = g_strconcat(bold, string, NULL);
1400 //    gchar *dbg_string = g_strconcat(bold, "DBG: ", string, NULL);
1401     g_free(string);
1402     return dbg_string;
1403 }
1404 
1405 static void
push_hash(pid_t controller,gchar * string)1406 push_hash(pid_t controller, gchar *string){
1407     pthread_mutex_lock(&string_hash_mutex);
1408     if (!c_string_hash){
1409         c_string_hash =
1410             g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
1411     }
1412     g_hash_table_replace(c_string_hash, GINT_TO_POINTER(controller), string);
1413     pthread_mutex_unlock(&string_hash_mutex);
1414 }
1415 #else
pop_hash(pid_t controller)1416 static gchar *pop_hash(pid_t controller){return g_strdup("");}
push_hash(pid_t controller,gchar * string)1417 static void push_hash(pid_t controller, gchar *string){return;}
1418 #endif
1419 
rfm_diagnostics_exit_string(gchar * tubo_string)1420 gchar *rfm_diagnostics_exit_string(gchar *tubo_string){
1421     gchar *string = NULL;
1422     if(strchr (tubo_string, '\n')) *strchr (tubo_string, '\n') = 0;
1423     const gchar *s = strchr (tubo_string, '(');
1424     int pid = -1;
1425     long id = 0;
1426     if (s) {
1427         s++;
1428         if(strchr (s, ')')) *strchr (s, ')') = 0;
1429         errno = 0;
1430         id = strtol(s, NULL, 10);
1431         if (!errno){
1432             pid = Tubo_child((pid_t) id);
1433         }
1434     }
1435     gchar *g = g_strdup_printf("%c[31m<%d>", 27, pid);
1436     gchar *c_string = pop_hash((pid_t)id);
1437     string = g_strconcat(g, " ", c_string, "\n", NULL);
1438     g_free(c_string);
1439     g_free(g);
1440     return string;
1441 }
1442 
1443 
1444 static gchar *
arg_string(char ** arg)1445 arg_string(char **arg){
1446     const gchar quote[]={'"', 0};
1447     gchar *g = g_strdup("");
1448     gchar **a = arg;
1449     for (;a && *a; a++){
1450         const gchar *q;
1451         if (strchr(*a, '*') || strchr(*a, '?') || strchr(*a, ' ')) q = quote;
1452         else q = "";
1453         gchar *gg = g_strconcat(g, " ", q, *a, q, NULL);
1454         g_free(g); g=gg;
1455     }
1456     return g;
1457 }
1458 
1459 static gchar *
arg_string_format(char ** arg)1460 arg_string_format(char **arg){
1461     const gchar quote[]={27, '[', '3', '1', 'm', '"', 0};
1462     const gchar bold[]={27, '[', '1', 'm', 0};
1463     gchar *g = g_strdup("");
1464     gchar **a = arg;
1465     for (;a && *a; a++){
1466         const gchar *q;
1467         if (strchr(*a, '*') || strchr(*a, '?') || strchr(*a, ' ')) q = quote;
1468         else q = "";
1469         gchar *gg = g_strconcat(g, " ", q, bold, *a, q, NULL);
1470         g_free(g); g=gg;
1471     }
1472     return g;
1473 }
1474 
1475 
rfm_diagnostics_start_string(gchar * command,pid_t controller,gboolean with_shell)1476 gchar *rfm_diagnostics_start_string(gchar *command, pid_t controller, gboolean with_shell){
1477     pid_t grandchild=Tubo_child (controller);
1478     push_hash(controller, g_strdup(command));
1479     gchar *g = g_strdup_printf ("%c[34m<%d>", 27, grandchild);
1480     gchar *gg;
1481 
1482 
1483     const gchar bold[]={27, '[', '1', 'm', 0};
1484     if (with_shell) {
1485         gchar *shell = rfm_shell();
1486         gg = g_strconcat (g, " ", shell, " ", bold, command, "\n", NULL);
1487         g_free (g);
1488         g_free(shell);
1489         return gg;
1490     }
1491     if (!strchr(command, '*') && !strchr(command,'?')){
1492         gg = g_strconcat (g, " ", bold, command, "\n", NULL);
1493         g_free (g);
1494         return gg;
1495     }
1496 
1497     gchar **ap;
1498     gint ac;
1499     if (g_shell_parse_argv (command, &ac, &ap, NULL)){
1500         gg = arg_string_format(ap);
1501         g_strfreev(ap);
1502         gchar *ggg = g_strconcat(g, " ", gg, "\n", NULL);
1503         g_free(g);
1504         g_free(gg);
1505         return ggg;
1506     }
1507     return g_strdup(g);
1508 }
1509 
rfm_diagnostics_start_string_argv(gchar ** argv,pid_t controller)1510 gchar *rfm_diagnostics_start_string_argv(gchar **argv, pid_t controller){
1511     pid_t grandchild=Tubo_child (controller);
1512 
1513 
1514     gchar *g = g_strdup_printf ("%c[34m<%d>", 27, grandchild);
1515     gchar *gg = arg_string(argv);
1516     push_hash(controller, g_strdup(gg));
1517     gg = arg_string_format(argv);
1518 
1519     gchar *ggg = g_strconcat(g, " ", gg, "\n", NULL);
1520     g_free(g);
1521     g_free(gg);
1522     return (ggg);
1523 }
1524 
1525 
1526 // This is a thread function, must have GDK mutex set for gtk commands...
1527 void
rfm_operate_stdout(void * user_data,void * stream,int childFD)1528 rfm_operate_stdout (void *user_data, void *stream, int childFD) {
1529     TRACE("*** rfm_operate_stdout: %s\n", (char *)stream);
1530     widgets_t *widgets_p = user_data;
1531     if (!widgets_p) return;
1532     view_t *view_p = widgets_p->view_p;
1533     rfm_global_t *rfm_global_p = rfm_global();
1534     if (rfm_global_p){
1535 	g_mutex_lock(rfm_global_p->status_mutex);
1536 	gint status = rfm_global_p->status;
1537 	g_mutex_unlock(rfm_global_p->status_mutex);
1538 	if (status == STATUS_EXIT) return;
1539     }
1540     if (view_p){
1541 	g_mutex_lock(view_p->mutexes.status_mutex);
1542 	gboolean status = view_p->flags.status;
1543 	g_mutex_unlock(view_p->mutexes.status_mutex);
1544 	if (status == STATUS_EXIT) return;
1545     }
1546     char *line;
1547     line = (char *)stream;
1548     NOOP ("FORK stdout: %s\n", line);
1549 
1550     if(line[0] == '\n') return;
1551     const gchar *exit_token = "Tubo-id exit:";
1552     gchar *recur = NULL;
1553     if (strstr(line, exit_token) && strstr(line, exit_token) != line){
1554         recur = g_strdup(strstr(line, exit_token));
1555         strcpy(strstr(line, exit_token), "\n");
1556     }
1557 
1558 
1559 /*    this is directly in tubo library
1560  *    if (!valid_ansi_sequence(line)) {
1561         NOOP("invalid ansi sequence!\n");
1562         return;
1563     }*/
1564 
1565 
1566     // eliminate all ^G found (as in nano output)
1567 
1568 
1569     //int bell=0x07; // bell
1570     int bs=0x08;   // backspace
1571     //int ht=0x09;   // horizontal tab
1572     //int lf=0x0a;   // linefeed
1573     //int vt=0x0b;   // vertical tab
1574     //int ff=0x0c;   // formfeed
1575     //int cr=0x0d;   // carriage return
1576 
1577     // apply all ^H (bs) found (as in rar output)
1578     int i, j;
1579     gchar *outline = g_strdup (line);
1580     for(i = 0, j = 0; line[i]; i++) {
1581 	if(line[i] == bs && j > 0){
1582             j--;
1583 	} else {
1584             outline[j] = line[i];
1585             j++;
1586         }
1587     }
1588     outline[j] = 0;
1589 
1590     //NOOP ("%s\n",outline);
1591     // Is the view still valid (valid_view?)
1592     TRACE("rfm_operate_stdout()...\n");
1593     if (!rfm_view_list_lock(view_p, "rfm_operate_stdout")) return;
1594 
1595     /*
1596      * FIXME: hwat's this hack for?
1597      * if (rfm_global_p && rfm_global_p->settings_widgets_p != widgets_p){
1598         rfm_view_list_unlock("rfm_operate_stdout");
1599         return;
1600     }*/
1601     if(strncmp (line, exit_token, strlen (exit_token)) == 0) {
1602         gchar *string = rfm_diagnostics_exit_string(line);
1603         rfm_threaded_diagnostics(widgets_p, "xffm/emblem_redball", string);
1604     } else {
1605 	rfm_threaded_diagnostics(widgets_p, NULL, g_strdup(outline));
1606     }
1607     g_free(outline);
1608     rfm_view_list_unlock("rfm_operate_stdout");
1609 
1610     // This is a bit hacky, to keep runaway output from hogging
1611     // up the gtk event loop.
1612     static gint count = 1;
1613     if (count % 20 == 0){
1614         usleep(100000);
1615     } else {
1616         usleep(1000);
1617     }
1618     if (recur) {
1619         rfm_operate_stdout (user_data, recur, childFD);
1620         g_free(recur);
1621     }
1622     return;
1623 }
1624 
1625 
1626 
1627 
1628 #if 1
1629 
1630 static void
insert_string(GtkTextBuffer * buffer,const gchar * s,GtkTextTag ** tags)1631 insert_string (GtkTextBuffer * buffer, const gchar * s, GtkTextTag **tags) {
1632     if(!s) return;
1633     GtkTextIter start, end, real_end;
1634     gint line = gtk_text_buffer_get_line_count (buffer);
1635     gchar *a = NULL;
1636 
1637 
1638     gchar esc[]={0x1B, '[', 0};
1639     gboolean head_section = strncmp(s, esc, strlen(esc));
1640     gchar *esc_location = strstr (s, esc);
1641     if(esc_location) {      //vt escape sequence
1642 	// do a split
1643 	    NOOP(stderr, "0.splitting %s\n", s);
1644 	gchar **split = g_strsplit(s, esc, -1);
1645 	if (!split) {
1646 	    DBG("insert_string(): split_esc barfed\n");
1647 	    return;
1648 	}
1649 
1650 	gchar **pp=split;
1651 	gint count = 0;
1652 	for (;pp && *pp; pp++, count++){
1653 	    if (strlen(*pp) == 0) continue;
1654 	    NOOP(stderr, "split %d: %s\n", count, *pp);
1655 	    if (count==0 && head_section){
1656 		insert_string (buffer, *pp, NULL);
1657 		continue;
1658 	    }
1659 	    gchar *code = *pp;
1660 	    if (*code == 'K'){
1661 		insert_string (buffer, "\n", NULL);
1662 		continue;
1663 	    }
1664 	    NOOP(stderr, "1.splitting %s\n", *pp);
1665 
1666 	    gchar **ss = g_strsplit(*pp, "m", 2);
1667 
1668 	    // Insert tags
1669 	    gchar **tags = NULL;
1670 	    if (strchr(ss[0],';')) {
1671 		NOOP(stderr, "2.splitting %s\n", ss[0]);
1672 		tags = g_strsplit(ss[0], ";", -1);
1673 	    } else {
1674 		tags = (gchar **)malloc(sizeof(gchar *) * 2 );
1675 		if (!tags) g_error("malloc: %s\n", strerror(errno));
1676 		tags[0] = g_strdup(ss[0]);
1677 		tags[1] = 0;
1678 	    }
1679 	    gchar **t = tags;
1680 	    gint tag_count = 0;
1681 	    for (;t && *t; t++)tag_count++;
1682 	    GtkTextTag **gtags = (GtkTextTag **)malloc((tag_count+1)*sizeof(GtkTextTag *));
1683 	    if (!gtags) g_error("malloc: %s\n", strerror(errno));
1684 	    memset(gtags, 0, (tag_count+1)*sizeof(GtkTextTag *));
1685 
1686 
1687 	    gint i;
1688 	    for (i=0,t = tags;t && *t; t++) {
1689 		if (!strcmp(*t,"01") || !strcmp(*t,"1")
1690 		    || !strcmp(*t,"05") || !strcmp(*t,"5"))
1691 		{
1692 		    gtags[i++] = resolve_tag(buffer, "xffm/bold");
1693 		    continue;
1694 		}
1695 		const gchar *tag = get_xffm_ansi_tag(*t);
1696 		if (!tag) {
1697 		    NOOP(stderr, "no xffm_ansi tag for %s\n", *t);
1698 		    continue;
1699 		}
1700 		gtags[i++] = resolve_tag(buffer, tag);
1701 		NOOP(stderr, "xffm_ansi_tag=%s\n", tag);
1702 	    }
1703 
1704 
1705 	    // Insert string
1706 	    insert_string (buffer, ss[1], gtags);
1707 	    g_free(gtags);
1708 
1709 	    g_strfreev(ss);
1710 
1711 	}
1712 	g_strfreev(split);
1713 	// done
1714 	return;
1715     }
1716 
1717     GtkTextMark *mark = gtk_text_buffer_get_mark (buffer, "rfm-ow");
1718     if(strchr (s, 0x0D)) {      //CR
1719         gchar *aa = g_strdup (s);
1720         *strchr (aa, 0x0D) = 0;
1721         insert_string (buffer, aa, tags);
1722         g_free (aa);
1723         aa = strchr (s, 0x0D) + 1;
1724         if(mark) {
1725             gtk_text_buffer_get_iter_at_line (buffer, &start, line);
1726             gtk_text_buffer_move_mark (buffer, mark, &start);
1727         }
1728         insert_string (buffer, aa, tags);
1729         g_free (a);
1730         // we're done
1731         return;
1732     }
1733 
1734     gchar *q = rfm_utf_string (s);
1735     /// this should be mutex protected since this function is being called
1736     //  from threads all over the place.
1737     static pthread_mutex_t insert_mutex=PTHREAD_MUTEX_INITIALIZER;
1738 #if 10
1739 // test 1
1740     pthread_mutex_lock(&insert_mutex);
1741 #if 10
1742 // test 3
1743     if(mark == NULL) {
1744         gtk_text_buffer_get_end_iter (buffer, &end);
1745         gtk_text_buffer_create_mark (buffer, "rfm-ow", &end, FALSE);
1746     } else {
1747         gtk_text_buffer_get_iter_at_mark (buffer, &end, mark);
1748     }
1749 
1750     gtk_text_buffer_get_iter_at_line (buffer, &start, line);
1751     gtk_text_buffer_get_end_iter (buffer, &real_end);
1752 
1753     // overwrite section
1754     gchar *pretext = gtk_text_buffer_get_text (buffer, &start, &end, TRUE);
1755     gchar *posttext = gtk_text_buffer_get_text (buffer, &end, &real_end, TRUE);
1756     long prechars = g_utf8_strlen (pretext, -1);
1757     long postchars = g_utf8_strlen (posttext, -1);
1758     long qchars = g_utf8_strlen (q, -1);
1759     g_free (pretext);
1760     g_free (posttext);
1761     if(qchars < postchars) {
1762         gtk_text_buffer_get_iter_at_line_offset (buffer, &real_end, line, prechars + qchars);
1763     }
1764     /////
1765     gtk_text_buffer_delete (buffer, &end, &real_end);
1766 #else
1767     gtk_text_buffer_get_end_iter (buffer, &end);
1768 
1769 // end test 3
1770 #endif
1771     if(tags) {
1772 	gint tag_count = 0;
1773 	GtkTextTag **tt = tags;
1774 	for (;tt && *tt; tt++)tag_count++;
1775 	switch (tag_count) { // This is hacky
1776 	    case 1:
1777 		gtk_text_buffer_insert_with_tags (buffer, &end, q, -1,
1778 			tags[0], NULL);
1779 		break;
1780 	    case 2:
1781 		gtk_text_buffer_insert_with_tags (buffer, &end, q, -1,
1782 			tags[0],tags[1], NULL);
1783 		break;
1784 	    default: // Max. 3 tags...
1785 		gtk_text_buffer_insert_with_tags (buffer, &end, q, -1,
1786 			tags[0],tags[1],tags[1], NULL);
1787 		break;
1788 	}
1789 
1790     } else {
1791 	NOOP(stderr, "gtk_text_buffer_insert %s\n", q);
1792         gtk_text_buffer_insert (buffer, &end, q, -1);
1793     }
1794     pthread_mutex_unlock(&insert_mutex);
1795 // end test 1
1796 #endif
1797     g_free (q);
1798     g_free (a);
1799     return;
1800 }
1801 
1802 
1803 
1804 #else
1805 
split_esc(const gchar * text)1806 static gchar **split_esc(const gchar *text){
1807     gchar escape[]={0x1b,0};
1808     return (g_strsplit(text, escape, -1));
1809 }
1810 static void
insert_string(GtkTextBuffer * buffer,const gchar * s,GtkTextTag * tag)1811 insert_string (GtkTextBuffer * buffer, const gchar * s, GtkTextTag * tag) {
1812     if(!s)
1813         return;
1814     GtkTextIter start,
1815       end,
1816       real_end;
1817     gint line = gtk_text_buffer_get_line_count (buffer);
1818     gchar *a = NULL;
1819     if(strchr (s, 0x1B)) {      //vt escape sequence
1820 	// do a split
1821 	gchar **split=split_esc(s);
1822 	if (!split) {
1823 	    DBG("insert_string(): split_esc barfed\n");
1824 	    return;
1825 	}
1826 	gchar **pp=split;
1827 	for (;pp && *pp; pp++){
1828 	    const gchar *tag=NULL;
1829 	    const gchar *sequence=NULL;
1830 	    sequence_t *p;
1831 	    for(p = sequence_p; p && p->sequence; p++) {
1832 		if(strncmp (*pp, p->sequence, strlen (p->sequence)) == 0) {
1833 		    tag=p->id;
1834 		    sequence=p->sequence;
1835 		    break;
1836 		}
1837 	    }
1838 	    if (!tag){
1839 		tag="xffm_tag/black";
1840 		DBG("VT escape secuence not reconized: <esc>%s\n",*pp);
1841 	    }
1842 	    gint offset=(sequence)?strlen(sequence):0;
1843 	    gchar *string=*pp+offset;
1844 	    NOOP("(%s) token:%s-->\"%s\"\n",
1845 		    tag, (sequence)?sequence:"None", string);
1846 	    insert_string (buffer, string, resolve_tag(buffer, tag));
1847 	}
1848 
1849 	g_strfreev(split);
1850 	// done
1851 	return;
1852     }
1853 
1854     GtkTextMark *mark = gtk_text_buffer_get_mark (buffer, "rfm-ow");
1855     if(strchr (s, 0x0D)) {      //CR
1856         gchar *aa = g_strdup (s);
1857         *strchr (aa, 0x0D) = 0;
1858         insert_string (buffer, aa, tag);
1859         g_free (aa);
1860         aa = strchr (s, 0x0D) + 1;
1861         if(mark) {
1862             gtk_text_buffer_get_iter_at_line (buffer, &start, line);
1863             gtk_text_buffer_move_mark (buffer, mark, &start);
1864         }
1865         insert_string (buffer, aa, tag);
1866         g_free (a);
1867         // we're done
1868         return;
1869     }
1870 
1871     gchar *q = rfm_utf_string (s);
1872     /// this should be mutex protected since this function is being called
1873     //  from threads all over the place.
1874     static pthread_mutex_t insert_mutex=PTHREAD_MUTEX_INITIALIZER;
1875 #if 10
1876 // test 1
1877     pthread_mutex_lock(&insert_mutex);
1878 #if 10
1879 // test 3
1880     if(mark == NULL) {
1881         gtk_text_buffer_get_end_iter (buffer, &end);
1882         gtk_text_buffer_create_mark (buffer, "rfm-ow", &end, FALSE);
1883     } else {
1884         gtk_text_buffer_get_iter_at_mark (buffer, &end, mark);
1885     }
1886 
1887     gtk_text_buffer_get_iter_at_line (buffer, &start, line);
1888     gtk_text_buffer_get_end_iter (buffer, &real_end);
1889 
1890     // overwrite section
1891     gchar *pretext = gtk_text_buffer_get_text (buffer, &start, &end, TRUE);
1892     gchar *posttext = gtk_text_buffer_get_text (buffer, &end, &real_end, TRUE);
1893     long prechars = g_utf8_strlen (pretext, -1);
1894     long postchars = g_utf8_strlen (posttext, -1);
1895     long qchars = g_utf8_strlen (q, -1);
1896     g_free (pretext);
1897     g_free (posttext);
1898     if(qchars < postchars) {
1899         gtk_text_buffer_get_iter_at_line_offset (buffer, &real_end, line, prechars + qchars);
1900     }
1901     /////
1902     gtk_text_buffer_delete (buffer, &end, &real_end);
1903 #else
1904     gtk_text_buffer_get_end_iter (buffer, &end);
1905 
1906 // end test 3
1907 #endif
1908     if(tag) {
1909         gtk_text_buffer_insert_with_tags (buffer, &end, q, -1, tag, NULL);
1910     } else {
1911         gtk_text_buffer_insert (buffer, &end, q, -1);
1912     }
1913     pthread_mutex_unlock(&insert_mutex);
1914 // end test 1
1915 #endif
1916     g_free (q);
1917     g_free (a);
1918     return;
1919 }
1920 #endif
1921 
1922 
1923 static void
set_font_family(GtkWidget * widget,const gchar * in_family,gboolean fixed)1924 set_font_family (GtkWidget * widget, const gchar *in_family, gboolean fixed) {
1925     if (!in_family) g_error("in_family cannot be NULL\n");
1926     if (!GTK_IS_WIDGET(widget)) return;
1927     gchar *family = g_object_get_data(G_OBJECT(widget), "font-family");
1928     gint fontsize = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget),	"fontsize"));
1929 
1930     gint newsize=8; // default font size.
1931     const gchar *p;
1932     if (fixed) p = getenv ("RFM_FIXED_FONT_SIZE");
1933     else p = getenv ("RFM_VARIABLE_FONT_SIZE");
1934     if(p && strlen (p)) {
1935 	errno=0;
1936 	long value = strtol(p, NULL, 0);
1937 	if (errno == 0){
1938 	    newsize = value;
1939 	}
1940     }
1941 
1942     if(newsize != fontsize || !family || strcmp(family, in_family)) {
1943 	NOOP(stderr, "XXX setting %s fontsize  %d -> %d \n", in_family, fontsize, newsize);
1944 	if (!family || strcmp(family, in_family)) {
1945 	    g_free(family);
1946 	    family = g_strdup(in_family);
1947 	    g_object_set_data(G_OBJECT(widget), "font-family", family);
1948 	}
1949 	fontsize = newsize;
1950 	g_object_set_data(G_OBJECT(widget),
1951 		"fontsize", GINT_TO_POINTER(fontsize));
1952 
1953 #if GTK_MAJOR_VERSION==2
1954 	gchar *font_id = g_strdup_printf("%s_font_desc", family);
1955         PangoFontDescription *font_desc = pango_font_description_new ();
1956         pango_font_description_set_family (font_desc, family);
1957         pango_font_description_set_size (font_desc, fontsize * PANGO_SCALE);
1958 	gtk_widget_modify_font (widget, font_desc);
1959 	g_free(font_id);
1960 	pango_font_description_free (font_desc);
1961 #else
1962         GtkStyleContext *style_context = gtk_widget_get_style_context (widget);
1963         gtk_style_context_add_class(style_context, GTK_STYLE_CLASS_VIEW );
1964         GtkCssProvider *css_provider = gtk_css_provider_new();
1965         GError *error=NULL;
1966         gchar *data = g_strdup_printf("* {\
1967 font-family: %s;\
1968 font-size: %dpx;\
1969 }", family, fontsize);
1970         gtk_css_provider_load_from_data (css_provider, data, -1, &error);
1971         g_free(data);
1972         if (error){
1973             fprintf(stderr, "gerror: %s\n", error->message);
1974             g_error_free(error);
1975         }
1976         gtk_style_context_add_provider (style_context, GTK_STYLE_PROVIDER(css_provider),
1977                                 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
1978 
1979 //	gtk_widget_override_font (widget, font_desc);
1980 #endif
1981 
1982 
1983     }
1984 }
1985 
1986 
1987 void
rfm_status(widgets_t * widgets_p,const gchar * id,...)1988 rfm_status (widgets_t * widgets_p, const gchar * id, ...) {
1989 
1990     if (!widgets_p) return;
1991     va_list var_args;
1992     char *t;
1993     GtkTextIter start,
1994       end;
1995     GtkTextBuffer *buffer;
1996     GdkPixbuf *icon;
1997     //gint icon_width = 0;
1998 
1999     if(!widgets_p->status || !GTK_IS_TEXT_VIEW (widgets_p->status)) {
2000 #ifdef DEBUG_NOOP
2001         /*DBG("rfm_status: status==NULL\n"); */
2002         va_start (var_args, id);
2003         do {
2004             t = va_arg (var_args, char *);
2005             if(t && strlen (t)) {
2006                 NOOP ("%s\n", t);
2007             }
2008         }
2009         while(t);
2010         va_end (var_args);
2011 #endif
2012         return;
2013     }
2014     // call this function when status line is created,
2015     // but that will not work for user changes in font size...
2016     if (id && strcmp(id, "xffm/emblem_terminal")==0) {
2017 	const gchar *family = getenv("RFM_FIXED_FONT_FAMILY");
2018 	if (!family || !strlen(family)) family="monospace";
2019 	set_font_family ((widgets_p->status), family, TRUE);
2020         // set_font_family (widgets_p->status, "monospace");
2021     } else {
2022 	const gchar *family = getenv("RFM_VARIABLE_FONT_FAMILY");
2023 	if (!family || !strlen(family)) family="sans";
2024          set_font_family (widgets_p->status, family, FALSE);
2025     }
2026      // call this function if you really want it when status line is created:
2027     // set_sans (widgets_p->status);
2028     /*gtk_text_view_set_justification ((GtkTextView *) widgets_p->status,GTK_JUSTIFY_LEFT); */
2029     buffer = gtk_text_view_get_buffer ((GtkTextView *) widgets_p->status);
2030     gtk_text_buffer_set_text (buffer, " ", -1);
2031     gtk_text_buffer_get_bounds (buffer, &start, &end);
2032 
2033     if(!id){
2034         id = "xffm/emote_cool";
2035     }
2036     icon = rfm_get_pixbuf (id, SIZE_BUTTON);
2037 
2038     if(icon && GDK_IS_PIXBUF(icon)) {
2039         gtk_text_buffer_insert_pixbuf (buffer, &start, icon);
2040         //icon_width = gdk_pixbuf_get_width (icon);
2041 	g_object_unref(icon);
2042     }
2043 
2044     {
2045         char *string = NULL;    /*,*tag; */
2046         gchar *f = NULL;
2047         va_start (var_args, id);
2048         do {
2049             t = va_arg (var_args, char *);
2050             if(t && strlen (t)) {
2051                 if(!f)
2052                     f = g_strdup ("");
2053                 string = g_strconcat (f, t, NULL);
2054                 g_free (f);
2055                 f = string;
2056             }
2057         }
2058         while(t);
2059         va_end (var_args);
2060         if(string) {
2061             insert_string (buffer, string, NULL);
2062             g_free (string);
2063         }
2064     }
2065     gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW  (widgets_p->status), FALSE);
2066     g_object_set_data (G_OBJECT (widgets_p->status), "clean", GINT_TO_POINTER(1));
2067 }
2068 
trim_diagnostics(GtkTextBuffer * buffer)2069 static void trim_diagnostics(GtkTextBuffer *buffer){
2070 // this is screwy in 3.12
2071     gint line_count = gtk_text_buffer_get_line_count (buffer);
2072     glong max_lines_in_buffer = 1000;
2073     if (getenv("RFM_MAXIMUM_DIAGNOSTIC_LINES") &&
2074 	    strlen(getenv("RFM_MAXIMUM_DIAGNOSTIC_LINES"))){
2075 	errno = 0;
2076 	max_lines_in_buffer =
2077 	    strtol(getenv("RFM_MAXIMUM_DIAGNOSTIC_LINES"), NULL, 10);
2078 	if (errno){
2079 	    max_lines_in_buffer = 1000;
2080 	}
2081 
2082     }
2083 #if GTK_MAJOR_VERSION==3
2084     if (line_count > 100*max_lines_in_buffer) {
2085 	gtk_text_buffer_set_text(buffer, "", -1); //clear buffer
2086     }
2087 #else
2088     GtkTextIter start, end;
2089        // this is screwy in 3.12
2090     if (line_count > max_lines_in_buffer) {
2091 	//gtk_text_buffer_set_text(buffer, "", -1); //clear buffer
2092 
2093 	NOOP(stderr, "line count is %d, deleting %d lines\n",
2094 		line_count, line_count-max_lines_in_buffer);
2095 	gtk_text_buffer_get_iter_at_line (buffer, &start, 0);
2096         // This is better, since one line is added at a time
2097 	gtk_text_buffer_get_iter_at_line (buffer, &end, 1);
2098 	//gtk_text_buffer_get_iter_at_line (buffer, &end, line_count - max_lines_in_buffer);
2099 	gtk_text_buffer_delete (buffer, &start, &end);
2100     }
2101 #endif
2102 }
2103 
2104 
2105     // For normal diagnostics, default is to show stdout if diagnostics
2106     // is visible, and to show diagnostics automatically whenever output
2107     // to stderr is detected.
2108 
2109 void
rfm_diagnostics(widgets_t * widgets_p,const gchar * id,...)2110 rfm_diagnostics (widgets_t * widgets_p, const gchar * id, ...
2111     ) {
2112     char *t;
2113     va_list var_args;
2114     GtkTextIter start, end;
2115     GtkTextBuffer *buffer;
2116     GdkPixbuf *icono = NULL;
2117 
2118     if (!widgets_p) {
2119         return;
2120     }
2121 
2122 #if 0
2123     view_t *view_p = widgets_p->view_p;
2124     // This is not necessary since the threads stdout/stderr
2125     // are tested for this condition before attempting to write.
2126     if (view_p){
2127 	g_mutex_lock(view_p->mutexes.status_mutex);
2128 	gboolean status = view_p->flags.status;
2129 	g_mutex_unlock(view_p->mutexes.status_mutex);
2130 	if (status == STATUS_EXIT) {
2131 	    TRACE("dead view 0x%x\n", GPOINTER_TO_INT(view_p));
2132 	    return;
2133 	}
2134     }
2135 #endif
2136     gboolean diagnostics_is_visible=rfm_diagnostics_is_visible (widgets_p);
2137 
2138     if(!diagnostics_is_visible) {
2139         TRACE( "!rfm_diagnostics_is_visible(diagnostics)\n");
2140        return;
2141     }
2142 //    if (!widgets_p->diagnostics || !gtk_widget_get_visible(widgets_p->diagnostics)){
2143     if ((widgets_p->diagnostics)==NULL){
2144         TRACE("!widgets_p->diagnostics\n");
2145 	return;
2146     }
2147 
2148     gboolean is_a_deskview=(widgets_p->diagnostics_window != NULL);
2149     if (is_a_deskview){
2150         NOOP ("is_a_deskview: gtk_widget_show_all\n");
2151 	if(getenv ("RFM_ENABLE_DESKTOP_DIAGNOSTICS") &&
2152 	    strlen (getenv ("RFM_ENABLE_DESKTOP_DIAGNOSTICS"))!=0)
2153 	{
2154 	    gtk_widget_show_all((widgets_p->diagnostics_window));
2155 	    //gtk_window_deiconify(GTK_WINDOW((widgets_p->diagnostics_window)));
2156 	}
2157     }
2158 
2159 //#define DEBUG_NOOP
2160 #ifdef DEBUG_NOOP
2161     fprintf(stderr, "rfm_diagnostics(0x%x, \"%s\"): \n",GPOINTER_TO_INT(widgets_p), id);
2162     va_start (var_args, id);
2163     do {
2164 	t = va_arg (var_args, char *);
2165 	if(t && strlen (t)) {
2166 	    fprintf (stderr, "%s", t);
2167 	}
2168     }
2169     while(t);
2170     va_end (var_args);
2171     //return;
2172 #endif
2173     if (!GTK_IS_TEXT_VIEW(widgets_p->diagnostics)) return;
2174     // call this function when diagnostics is created,
2175     // but that only works for desktop diagnostics,
2176     // not for iconview diagnostics, I wonder why...
2177     const gchar *family = getenv("RFM_FIXED_FONT_FAMILY");
2178     if (!family || !strlen(family)) family="monospace";
2179     set_font_family ((widgets_p->diagnostics), family, TRUE);
2180 
2181     /****  */
2182     buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW ((widgets_p->diagnostics)));
2183 
2184     /*NOOP("NOOP:rfm_diagnostics\n"); */
2185     gtk_text_buffer_get_bounds (buffer, &start, &end);
2186 
2187     GtkTextTag **tags = NULL;
2188     //NOOP("DIAGNOSTICS: id= %s\n",id);
2189     if(id) {
2190         if(strncmp (id, "xffm_tag/", strlen ("xffm_tag/")) == 0) {
2191 	    tags = (GtkTextTag **)malloc(2*sizeof(GtkTextTag *));
2192 	    if (!tags) g_error("malloc: %s\n", strerror(errno));
2193 	    tags[0] = resolve_tag (buffer, id);
2194 	    tags[1] = NULL;
2195         } else {
2196             icono = rfm_get_pixbuf (id, SIZE_BUTTON);
2197         }
2198     }
2199     if(icono) {
2200         gtk_text_buffer_insert_pixbuf (buffer, &end, icono);
2201 	g_object_unref(icono);
2202     }
2203 
2204     va_start (var_args, id);
2205     do {
2206         t = va_arg (var_args, char *);
2207         if(t && strlen (t)) {
2208             insert_string (buffer, t, tags);
2209         }
2210     }
2211     while(t);
2212     g_free(tags);
2213     va_end (var_args);
2214 
2215     // trim
2216     trim_diagnostics(buffer);
2217 
2218     // scroll
2219     gtk_text_buffer_get_bounds (buffer, &start, &end);
2220     GtkTextMark *mark = gtk_text_buffer_create_mark (buffer, "scrolldown", &end, FALSE);
2221     gtk_text_view_scroll_mark_onscreen (GTK_TEXT_VIEW ((widgets_p->diagnostics)), mark);
2222     gtk_text_buffer_delete_mark(buffer, mark);
2223 
2224     /*    gint line_count = gtk_text_buffer_get_line_count (buffer);
2225     gtk_text_buffer_get_iter_at_line (buffer, &start, line_count+1);
2226 
2227     gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW ((widgets_p->diagnostics)),
2228                               &start,
2229                               0.0,
2230                               TRUE,
2231                               0.0,
2232                               0.0);*/
2233    /* gtk_text_buffer_get_bounds (buffer, &start, &end);
2234     GtkTextMark *mark = gtk_text_buffer_get_mark (buffer, "scrollmark2");
2235     if (mark == NULL){
2236 	mark = gtk_text_buffer_create_mark (buffer, "scrollmark2", &end, FALSE);
2237     } else {
2238 	gtk_text_buffer_move_mark   (buffer,  mark  ,&end);
2239     }
2240     gtk_text_view_scroll_mark_onscreen (GTK_TEXT_VIEW ((widgets_p->diagnostics)), mark);*/
2241 
2242 
2243 }
2244 
2245 void *
show_text_f(gpointer data)2246 show_text_f (gpointer data) {
2247     widgets_t * widgets_p = data;
2248     if(!widgets_p) return NULL;
2249     //gboolean diagnostics_is_visible=rfm_diagnostics_is_visible (widgets_p);
2250     gboolean is_a_deskview = (widgets_p->diagnostics_window != NULL);
2251 
2252 
2253 
2254     if(is_a_deskview){
2255 	if (getenv ("RFM_ENABLE_DESKTOP_DIAGNOSTICS") &&
2256 	  strlen (getenv ("RFM_ENABLE_DESKTOP_DIAGNOSTICS"))!=0)
2257 	{
2258 	    gtk_widget_show_all((widgets_p->diagnostics_window));
2259 	    //gtk_window_deiconify(GTK_WINDOW((widgets_p->diagnostics_window)));
2260 	}
2261         return NULL;
2262     }
2263 
2264     // If already visible, then there's nothing more to do.
2265     // if (diagnostics_is_visible) return;
2266 
2267     GtkWidget *vpane = g_object_get_data(G_OBJECT(widgets_p->paper), "vpane");
2268     if(vpane){
2269 	GtkAllocation allocation;
2270 	gtk_widget_get_allocation (vpane, &allocation);
2271 	if (allocation.height > 50) {
2272 	    gdouble position =
2273 		gtk_paned_get_position (GTK_PANED(vpane));
2274 	    if(position > allocation.height * 0.90) {
2275 		gtk_paned_set_position (GTK_PANED (vpane), allocation.height * 0.75);
2276 	    }
2277 	}
2278     }
2279     return NULL;
2280 }
2281 
2282 void *
rfm_show_text(gpointer data)2283 rfm_show_text (gpointer data) {
2284     widgets_t * widgets_p = data;
2285     if(!widgets_p) return NULL;
2286     return rfm_context_function(show_text_f, data);
2287 }
2288 
2289 gboolean
rfm_diagnostics_is_visible(widgets_t * widgets_p)2290 rfm_diagnostics_is_visible (widgets_t * widgets_p) {
2291     if (!widgets_p) return FALSE;
2292     rfm_global_t *rfm_global_p = rfm_global();
2293     if (!rfm_global_p) return TRUE;
2294     if (rfm_global_p->settings_widgets_p == widgets_p) return TRUE;
2295 
2296     // Are we dealing with a deskview?
2297     view_t *view_p = widgets_p->view_p;
2298 
2299     if (view_p->flags.type == DESKVIEW_TYPE){
2300 	// Does the deskview output window exist?
2301 	// If no, then create it.
2302 	if ((widgets_p->diagnostics_window)==NULL){
2303 	    rfm_create_diagnostics_window(widgets_p);
2304 	}
2305 	// We return TRUE even if item is iconized
2306 	return TRUE;
2307     }
2308 
2309     // By this point we should be dealing with views with diagnostics area.
2310     // If the view does not have a diagnostics area defined, return false.
2311     if(widgets_p->diagnostics == NULL) {
2312 	return FALSE;
2313     }
2314 
2315 #if 0
2316     // By now we should have a diagnostics area defined within the vertical pane.
2317     GtkWidget *vpane = g_object_get_data(G_OBJECT(widgets_p->paper), "vpane");
2318     if(vpane){
2319 	// Whatever...
2320 	return TRUE;
2321 /*	GtkAllocation allocation;
2322 	gtk_widget_get_allocation (widgets_p->vpane, &allocation);
2323 	if(gtk_paned_get_position (
2324 		    GTK_PANED(widgets_p->vpane)) > allocation.height * 0.95)
2325 	{
2326 	    return FALSE;
2327 	}*/
2328     }
2329 #endif
2330     return TRUE;
2331 }
2332 
2333 void *
rfm_hide_text(gpointer data)2334 rfm_hide_text (gpointer data) {
2335     widgets_t * widgets_p = data;
2336     if(widgets_p->diagnostics==NULL){
2337         return NULL;
2338     }
2339     GtkWidget *vpane = g_object_get_data(G_OBJECT(widgets_p->paper), "vpane");
2340     if(!vpane){
2341         return FALSE;
2342     }
2343 	NOOP(stderr, "vpane = 0x%x\n", GPOINTER_TO_INT(vpane));
2344 
2345     GtkAllocation allocation;
2346     gtk_widget_get_allocation (vpane, &allocation);
2347     NOOP(stderr, "HACK set pane position to %d\n", allocation.height);
2348 
2349     gtk_paned_set_position (GTK_PANED (vpane), allocation.height);
2350     gtk_paned_set_position (GTK_PANED (vpane), 10000);
2351 
2352     return NULL;
2353 }
2354 
2355 void *
clear_text_f(void * data)2356 clear_text_f (void *data) {
2357     widgets_t * widgets_p = data;
2358     GtkTextIter start,
2359       end;
2360     GtkTextBuffer *buffer;
2361     buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW ((widgets_p->diagnostics)));
2362     gtk_text_buffer_get_bounds (buffer, &start, &end);
2363     gtk_text_buffer_delete (buffer, &start, &end);
2364     if (widgets_p->diagnostics_window==NULL) {
2365 	// This is not applicable to diagnostics_window:
2366 	rfm_hide_text (widgets_p);
2367     }
2368     g_object_ref (G_OBJECT(buffer));
2369     gtk_text_view_set_buffer(GTK_TEXT_VIEW ((widgets_p->diagnostics)), gtk_text_buffer_new(NULL));
2370     g_object_ref_sink (G_OBJECT(buffer));
2371     g_object_unref (G_OBJECT(buffer));
2372     return NULL;
2373 }
2374 
2375 void
rfm_clear_text(widgets_t * widgets_p)2376 rfm_clear_text (widgets_t * widgets_p) {
2377     if(widgets_p->diagnostics==NULL) return;
2378     rfm_context_function(clear_text_f, widgets_p);
2379 }
2380 
2381 void
rfm_clear_text_window(GtkButton * button,gpointer data)2382 rfm_clear_text_window (GtkButton * button, gpointer data) {
2383 
2384     widgets_t *widgets_p = (widgets_t *) data;
2385     if(widgets_p->diagnostics==NULL)
2386         return;
2387     rfm_clear_text (widgets_p);
2388     gtk_widget_grab_focus (widgets_p->paper);
2389     view_t *view_p = widgets_p->view_p;
2390     rfm_update_status_line (view_p);
2391     // do reselection...
2392     if (view_p->reselect_list){
2393 	GSList *tmp = view_p->reselect_list;
2394 	if (rfm_population_try_read_lock(view_p, "rfm_clear_text_window")){
2395 	    for (; tmp && tmp->data; tmp=tmp->next){
2396 		TRACE("reselecting %s \n", (gchar *)tmp->data);
2397 		population_t **population_pp = view_p->population_pp;
2398 		for (;population_pp && *population_pp; population_pp++){
2399 		    population_t *population_p = *population_pp;
2400 		    if (!population_p->en) continue;
2401 		    if (strcmp(population_p->en->path, (gchar *)tmp->data)==0){
2402 			// FIXME: rfm library should not reference
2403 			// rodent library (matter of principle)
2404 			rfm_select_pixbuf (view_p, population_p);
2405 			rfm_expose_item (view_p, population_p);
2406 		    }
2407 		}
2408 	    }
2409 	    rfm_population_read_unlock(view_p, "rfm_clear_text_window");
2410 	}
2411 	tmp = view_p->reselect_list;
2412 	for (; tmp && tmp->data; tmp=tmp->next){g_free(tmp->data);}
2413 	g_slist_free(view_p->reselect_list);
2414         view_p->reselect_list = NULL;
2415     }
2416     //under certain condition, like doing a clear after a threaded remove,
2417     //update status line may race with invalid view_p->selection_list
2418     //rfm_update_status_line (widgets_p->view_p);
2419 }
2420 
2421 void
rfm_set_bin_image(GtkWidget * bin,const gchar * icon_id,gint size)2422 rfm_set_bin_image(GtkWidget *bin, const gchar *icon_id, gint size){
2423     if (!bin || !GTK_IS_WIDGET(bin)) {
2424         g_warning("rfm_set_bin_image(): incorrect function call\n");
2425         return;
2426     }
2427     GtkWidget *box = gtk_bin_get_child(GTK_BIN(bin));
2428     GtkWidget *icon = g_object_get_data(G_OBJECT(bin),"icon");
2429 
2430     if (icon){
2431         gtk_container_remove(GTK_CONTAINER(box), icon);
2432     }
2433     if(icon_id) {
2434         GdkPixbuf *pb = rfm_get_pixbuf (icon_id, size);
2435         GtkWidget *image = gtk_image_new_from_pixbuf (pb);
2436 	gtk_box_pack_start(GTK_BOX(box), image, FALSE, FALSE,0);
2437         g_object_set_data(G_OBJECT(bin), "icon", image);
2438 	gtk_widget_show(image);
2439 	g_object_unref(pb);
2440     } else {
2441         g_object_set_data(G_OBJECT(bin), "icon", NULL);
2442     }
2443 }
2444 
2445 void
rfm_set_bin_markup(GtkWidget * bin,const char * text)2446 rfm_set_bin_markup(GtkWidget *bin, const char *text){
2447     if (!bin || !GTK_IS_WIDGET(bin)) {
2448         g_warning("rfm_set_bin_markup(): incorrect function call\n");
2449         return;
2450     }
2451     GtkLabel *label = g_object_get_data(G_OBJECT(bin), "label");
2452     gtk_label_set_markup(label, (text)?text:"");
2453 }
2454 
2455 static void
set_bin_contents(GtkWidget * bin,const char * icon_id,const char * text,gint size)2456 set_bin_contents(GtkWidget *bin, const char *icon_id, const char *text, gint size){
2457     GtkWidget *child = gtk_bin_get_child(GTK_BIN(bin));
2458     if (child) gtk_container_remove(GTK_CONTAINER(bin), child);
2459     child = rfm_hbox_new(FALSE,0);
2460     gtk_widget_set_size_request (child, -1, 12);
2461     gtk_container_add(GTK_CONTAINER(bin), child);
2462 
2463     GtkWidget *label = gtk_label_new("");
2464     g_object_set_data(G_OBJECT(bin), "label", label);
2465     gtk_box_pack_end(GTK_BOX(child), label, TRUE, FALSE,0);
2466 
2467     rfm_set_bin_markup(bin, text);
2468     rfm_set_bin_image(bin, icon_id, size);
2469     gtk_widget_show_all (bin);
2470 }
2471 
2472 GtkWidget *
rfm_dialog_button(const char * icon_id,const char * text)2473 rfm_dialog_button (const char *icon_id, const char *text) {
2474     GtkWidget *button = gtk_button_new ();
2475     set_bin_contents(button, icon_id, text, SIZE_BUTTON);
2476     return button;
2477 
2478 }
2479 
2480 
2481 GtkWidget *
rfm_toggle_button(const char * icon_id,const char * text)2482 rfm_toggle_button (const char *icon_id, const char *text) {
2483     GtkWidget *button = gtk_toggle_button_new ();
2484     set_bin_contents(button, icon_id, text, SIZE_BUTTON);
2485     return button;
2486 }
2487 
2488 
2489 GtkWidget *
rfm_pathbar_button(const char * icon_id,const char * text)2490 rfm_pathbar_button (const char *icon_id, const char *text) {
2491     //GtkWidget *pb_button = gtk_toggle_button_new ();
2492     GtkWidget *pb_button = gtk_button_new ();
2493 
2494     g_object_set (pb_button,
2495             "can-focus", FALSE,
2496             "relief", GTK_RELIEF_NONE,
2497             NULL);
2498     g_object_set_data(G_OBJECT(pb_button), "name", text?g_strdup(text):NULL);
2499     gchar *markup = NULL;
2500     if (text) {
2501         gchar *v = rfm_utf_string(text);
2502         gchar *g = g_markup_escape_text(v, -1);
2503         g_free(v);
2504         markup = g_strdup_printf("<span size=\"x-small\">%s</span>", g);
2505         g_free(g);
2506     }
2507     set_bin_contents(pb_button, icon_id, markup, 12);
2508     g_free(markup);
2509     return pb_button;
2510 }
2511 
2512 
2513 
toggle_pathbar(GtkWidget * pathbar,const gchar * path)2514 static void toggle_pathbar(GtkWidget *pathbar, const gchar *path){
2515     GList *children_list = gtk_container_get_children(GTK_CONTAINER(pathbar));
2516     GList *children;
2517 
2518     GtkRequisition minimum;
2519     GtkAllocation allocation;
2520     gtk_widget_get_allocation(pathbar, &allocation);
2521     NOOP("pathbar width=%d\n", allocation.width);
2522     gint width = allocation.width;
2523 
2524     // First we hide all buttons, except "RFM_ROOT"
2525     children = g_list_last(children_list);
2526     for (;children && children->data; children=children->prev){
2527         gchar *name = g_object_get_data(G_OBJECT(children->data), "name");
2528         if (strcmp(name, "RFM_ROOT")==0) {
2529 #if GTK_MAJOR_VERSION>=3
2530             gtk_widget_get_preferred_size(GTK_WIDGET(children->data),
2531                     &minimum, NULL);
2532 #else
2533     {
2534      GtkAllocation a;
2535      gtk_widget_get_allocation(GTK_WIDGET(children->data), &a);
2536      minimum.width = a.width;
2537     }
2538 
2539 #endif
2540             width -= minimum.width;
2541             continue;
2542         }
2543         gtk_widget_hide(GTK_WIDGET(children->data));
2544     }
2545 
2546     // Find first item to place in pathbar.
2547     // This item *must* be equal to path, if path is in buttons.
2548 
2549     children = g_list_last(children_list);
2550     GList *active = children;
2551     // If path is not in the buttons, then the first to map
2552     // will be the last path visited.
2553     if (path) for (;children && children->data; children=children->prev){
2554         const gchar *pb_path =
2555             g_object_get_data(G_OBJECT(children->data), "path");
2556         if (!pb_path) continue;
2557         if (strcmp(path, pb_path)==0) {
2558             active = children;
2559             break;
2560         }
2561     }
2562 
2563     // Show active button
2564     gtk_widget_show(GTK_WIDGET(active->data));
2565 #if GTK_MAJOR_VERSION>=3
2566     gtk_widget_get_preferred_size(GTK_WIDGET(active->data), &minimum, NULL);
2567 #else
2568     {
2569      GtkAllocation a;
2570      gtk_widget_get_allocation(GTK_WIDGET(active->data), &a);
2571      minimum.width = a.width;
2572     }
2573 #endif
2574     width -= minimum.width;
2575 
2576     // Work backwards from active button we show buttons that will fit.
2577     children = active->prev;
2578     for (;children && children->data; children=children->prev){
2579         gchar *name = g_object_get_data(G_OBJECT(children->data), "name");
2580         if (strcmp(name, "RFM_ROOT")==0) continue;
2581         gtk_widget_get_allocation(GTK_WIDGET(children->data), &allocation);
2582         width -= allocation.width;
2583         if (width < 0) break;
2584         gtk_widget_show(GTK_WIDGET(children->data));
2585     }
2586 
2587     // Now we work forwards, showing buttons that fit.
2588     children = active->next;
2589     for (;children && children->data; children=children->next){
2590        gchar *name = g_object_get_data(G_OBJECT(children->data), "name");
2591         if (strcmp(name, "RFM_ROOT")==0) continue;
2592         gtk_widget_get_allocation(GTK_WIDGET(children->data), &allocation);
2593         width -= allocation.width;
2594         if (width < 0) break;
2595         gtk_widget_show(GTK_WIDGET(children->data));
2596     }
2597 
2598     // Finally, we differentiate active button.
2599     children = g_list_first(children_list);
2600     for (;children && children->data; children=children->next){
2601         gchar *name = g_object_get_data(G_OBJECT(children->data), "name");
2602         if (strcmp(name, "RFM_ROOT")==0) continue;
2603         if (!path) {
2604             // no path means none is differentiated.
2605             gchar *v = rfm_utf_string(name);
2606             gchar *g = g_markup_escape_text(v, -1);
2607             g_free(v);
2608             gchar *markup = g_strdup_printf("<span size=\"x-small\" color=\"blue\" bgcolor=\"#dcdad5\">%s</span>", g);
2609             rfm_set_bin_markup(GTK_WIDGET(children->data), markup);
2610             g_free(g);
2611             g_free(markup);
2612             continue;
2613         }
2614         const gchar *pb_path =
2615             g_object_get_data(G_OBJECT(children->data), "path");
2616         if (!pb_path){
2617             g_warning("rfm_update_pathbar(): pb_path is null\n");
2618             continue;
2619         }
2620         if (!strlen(pb_path)) pb_path=G_DIR_SEPARATOR_S;//?
2621         if (strcmp(pb_path, path)==0) {
2622             gchar *v = rfm_utf_string(name);
2623             gchar *g = g_markup_escape_text(v, -1);
2624             g_free(v);
2625             gchar *markup = g_strdup_printf("<span size=\"x-small\" color=\"red\"bgcolor=\"#dcdad5\">%s</span>", g);
2626             rfm_set_bin_markup(GTK_WIDGET(children->data), markup);
2627             g_free(g);
2628             g_free(markup);
2629         }
2630         else {
2631             gchar *v = rfm_utf_string(name);
2632             gchar *g = g_markup_escape_text(v, -1);
2633             g_free(v);
2634             gchar *markup = g_strdup_printf("<span size=\"x-small\" color=\"blue\"bgcolor=\"#dcdad5\">%s</span>", g);
2635             rfm_set_bin_markup(GTK_WIDGET(children->data), markup);
2636             g_free(g);
2637             g_free(markup);
2638         }
2639     }
2640     g_list_free(children_list);
2641 }
2642 
2643 
rfm_update_pathbar_f(void * data)2644 static void *rfm_update_pathbar_f(void *data){
2645     void **arg = data;
2646     GtkWidget *pathbar = arg[0];
2647     gchar *path =arg[1];
2648 
2649     if (!pathbar) return NULL;
2650     if (!path){
2651         NOOP("##### toggle_pathbar(pathbar, NULL)\n");
2652         toggle_pathbar(pathbar, NULL);
2653         return NULL;
2654     }
2655 
2656     // Trim pathbar.
2657     gchar **paths;
2658     if (strcmp(path, G_DIR_SEPARATOR_S)==0){
2659         paths = (gchar **)malloc(2*sizeof(gchar *));
2660         if (!paths){
2661             g_warning("rfm_update_pathbar(): cannot malloc\n");
2662             return NULL;
2663         }
2664         paths[1]=NULL;
2665     } else {
2666         paths = g_strsplit(path, G_DIR_SEPARATOR_S, -1);
2667         g_free(paths[0]);
2668     }
2669     paths[0]= g_strdup(G_DIR_SEPARATOR_S);
2670 
2671     GList *children_list = gtk_container_get_children(GTK_CONTAINER(pathbar));
2672     GList *children = children_list;
2673     gint i=0;
2674     gchar *pb_path = NULL;
2675     for (;children && children->data; children=children->next){
2676         gchar *name = g_object_get_data(G_OBJECT(children->data), "name");
2677         if (strcmp(name, "RFM_ROOT")==0 || strcmp(name, "<")==0) continue;
2678         //gchar *p = g_strdup_printf("%s%c", paths[i], G_DIR_SEPARATOR);
2679         NOOP("(%d) comparing %s <--> %s\n", i, name, paths[i]);
2680         if (paths[i] && strcmp(name, paths[i]) == 0){
2681             g_free(pb_path);
2682             const gchar *p = g_object_get_data(G_OBJECT(children->data), "path");
2683             pb_path = g_strdup(p);
2684             i++;
2685             continue;
2686         }
2687         // Eliminate tail (only if tail will differ)
2688         if (paths[i] == NULL) break;
2689         NOOP("Zapping tail: \"%s\"\n", paths[i]);
2690         GList *tail = children;
2691         for (;tail && tail->data; tail = tail->next){
2692             gchar *name  = g_object_get_data(G_OBJECT(tail->data), "name");
2693             g_free(name);
2694             gtk_container_remove(GTK_CONTAINER(pathbar), GTK_WIDGET(tail->data));
2695         }
2696         break;
2697     }
2698     g_list_free(children_list);
2699 
2700     // Add new tail
2701     gpointer callback =g_object_get_data(G_OBJECT(pathbar), "callback");
2702     if (strcmp(path, "RFM_MODULE")) for (;paths[i]; i++){
2703         GtkWidget *pb_button = rfm_pathbar_button(NULL,
2704                 strlen(paths[i])?paths[i]:G_DIR_SEPARATOR_S);
2705 #if GTK_MAJOR_VERSION>=3
2706         gtk_container_add(GTK_CONTAINER(pathbar), pb_button);
2707 
2708 #else
2709         gtk_box_pack_start(GTK_BOX(pathbar), pb_button, FALSE, FALSE, 1);
2710 #endif
2711         gchar *g = (pb_path!=NULL)?
2712             g_strdup_printf("%s%s%s",pb_path,
2713                     strcmp(pb_path,G_DIR_SEPARATOR_S)?
2714                     G_DIR_SEPARATOR_S:"", paths[i]):
2715             g_strdup(paths[i]);
2716         g_free(pb_path);
2717         pb_path = g;
2718         NOOP("+++***** setting pbpath --> %s\n", pb_path);
2719         g_object_set_data(G_OBJECT(pb_button), "path", g_strdup(pb_path));
2720         g_signal_connect (G_OBJECT(pb_button) , "clicked", G_CALLBACK (callback), pathbar);
2721 
2722     }
2723     g_free(pb_path);
2724     g_strfreev(paths);
2725 
2726     // show what fits
2727     toggle_pathbar(pathbar, path);
2728     g_free(path);
2729     return NULL;
2730 }
2731 
rfm_update_pathbar(GtkWidget * pathbar,const gchar * path)2732 void rfm_update_pathbar(GtkWidget *pathbar, const gchar *path){
2733     void *arg[]={pathbar, path?g_strdup(path):NULL};
2734     rfm_context_function(rfm_update_pathbar_f, arg);
2735 }
2736 
2737 
2738 static void *
dialog_run_response_f(void * data)2739 dialog_run_response_f(void *data){
2740     GtkDialog *dialog = data;
2741     gint response = gtk_dialog_run (dialog);
2742     return GINT_TO_POINTER(response);
2743 }
2744 
2745 // Thread OK:
2746 gint
rfm_dialog_run_response(GtkWidget * dialog)2747 rfm_dialog_run_response(GtkWidget *dialog){
2748     return GPOINTER_TO_INT(
2749 	    rfm_context_function(dialog_run_response_f, dialog));
2750 }
2751 
2752 // Thread OK:
2753 gboolean
rfm_confirm(widgets_t * widgets_p,gint type,const gchar * text,const gchar * action_false,const gchar * action_true)2754 rfm_confirm (widgets_t * widgets_p,
2755 	// type: GTK_MESSAGE_INFO, GTK_MESSAGE_WARNING, GTK_MESSAGE_QUESTION, GTK_MESSAGE_ERROR
2756 	gint type,
2757 //	GtkMessageType type,
2758 	const gchar * text,
2759 	const gchar * action_false,  // if NULL, button not shown
2760 	const gchar * action_true   // if NULL, "Ok" button shown
2761 	) {
2762     void *result;
2763     void *arg[] = {
2764 	widgets_p,
2765 	GINT_TO_POINTER(type),
2766 	(void *)text,
2767 	(void *)action_false,
2768 	(void *)action_true
2769     };
2770 	result = rfm_context_function(confirm_f, arg);
2771     return GPOINTER_TO_INT(result);
2772 }
2773 
2774 
2775 gchar *
rfm_get_response(widgets_t * widgets_p,const gchar * ptext,const gchar * default_value,gboolean hidden)2776 rfm_get_response (widgets_t * widgets_p, const gchar * ptext, const gchar *default_value, gboolean hidden) {
2777     void *arg[]={
2778 	(void *)widgets_p,
2779 	(void *)ptext,
2780 	(void *)default_value,
2781 	(void *)GINT_TO_POINTER(hidden),
2782 	NULL
2783     };
2784     gchar *passphrase = rfm_context_function(get_response_f, arg);
2785     return passphrase;
2786 }
2787 
2788 
2789 
2790 // Thread OK:
rfm_confirm_sudo(widgets_t * widgets_p,const gchar * tgt,const gchar * failed,const gchar * operation)2791 gboolean rfm_confirm_sudo(widgets_t *widgets_p,
2792        const gchar *tgt,
2793        const gchar *failed,
2794        const gchar *operation){
2795 
2796 	gchar *altoperation=
2797 	    g_strconcat(_("sudo"), " ", operation, NULL);
2798 	gchar *text=g_strconcat(
2799 	    _("Command:"), " \"", operation, "\"",
2800 	    "\n\n",
2801 	    failed,"\n",
2802 	    _("Permission denied"), ": ", tgt, "\n\n",
2803 	     _("Try to approach a problem from different angles."), "\n\n",
2804 	    _("Do you want to retry?"), "\n",
2805 	     	    _("Alternate:"), " \"", altoperation, "\"",
2806 	    "\n",
2807 	    NULL
2808 		);
2809 	gboolean retval= rfm_confirm(widgets_p, GTK_MESSAGE_QUESTION,
2810 		text, _("No"), altoperation);
2811 	g_free(altoperation);
2812 	g_free(text);
2813 	return retval;
2814 }
2815 
2816