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