Interactive PipeReads?

I’ve gotten tired of adding a new function to my config for every wallpaper I might use just so each can have a different colorset, so I thought I would add a some interactivity to my setup. I wrote a little GTK color selector that outputs a 6-digit hex value with the intention of having FVWM somehow read this into a ColorSet with a PipeRead. PipeRead, however, doesn’t seem built for this: no window appears with the command and the color isn’t even set to the default output. Here is the menu command used:[code]AddToMenu MenuColorSelect

  • “Colorset 3 bg” PipeRead ‘$[fvwm_scripts]/colorset 3 bg’[/code]
    And the script colorset:#!/bin/bash echo "Colorset $1 $2 #`./colorselect`"
    The program colorselect simply spawns a window and outputs a color value when closed.

Is it even possible to do this? Can PipeReads be used interactively in this fashion (without pausing the entire rest of the window manager while waiting)?

Perhaps not via PipeRead directly, but then FvwmForm was built to handle your situation.

– Thomas Adam

When I try to do the same (but with gksu or ssh-askpass instead of your colorselect), fvwm is frozen since it waits for the command, and hence it can’t grant the request from gksu to have its window displayed. I have to kill gksu and restart fvwm (using FvwmCommand) to perform the action.

I had a look at FvwmForm and didn’t see any colorchooser related stuff.

Another solution I could suggest is to use module FvwmCommandS and replace PipeRead colorset by Exec colorset which is a script which does

FvwmCommand "Colorset $1 $2 #`./colorselect`"

(in my config, I had to indicate the full path of colorselect)

By the way, could you release the source of the colorselect program?

Edit –

I tried it, it works.

I haven’t figured out how to actually use it, but FvwmGtk looks like it could do what FvwmForm can’t, and does have a color select widget. FvwmCommand however is quite easy to use and a whole lot more flexible. Thank you very much zonk, this opens up a lot of possibilities. And I’m a little flattered that someone has an interest in something I wrote :slight_smile: though it is dirt simple and not even totally done. I wanted to be able to pass in a hex value as a starting color so you could cancel out, but I’ve only just laid some preliminary code for that as of yet (the rest would probably double the code size), and now I wonder if it wouldn’t be possible to have dynamic updates. But I’ll glady release what I have, it’s small enough just to include in a post. I’ve stripped out the unnecessary parts for clarity’s sake, but left in some comments in case anyone else is new to GTK (this is my first GUI app since my VisualBasic days years and years ago :stuck_out_tongue:).

So for the record, the way to add a GUI app to your FVWM config using FvwmCommand is:
[list][*]Start up FvwmCommandS somewhere in your config, such as:[code]DestroyFunc StartFunction
AddToFunc StartFunction

  • I Module FvwmCommandS[/code][/:m]
    [
    ]Make a script that runs the FVWM command you want with the program you want via FvwmCommand, such as:#!/bin/bash FvwmCommand "Colorset $1 $2 #`/home/norfenstein/.fvwm/scripts/colorselect`"[/:m]
    [
    ]Exec that script somewhere in your config, like so:[code]DestroyMenu MenuColorSelect
    AddToMenu MenuColorSelect
  • “Colorset 3 fg” Exec $[fvwm_scripts]/colorset 3 fg
  • “Colorset 3 bg” Exec $[fvwm_scripts]/colorset 3 bg[/code][/*:m][/list:u]
    Don’t know why FvwmCommand requires a full path to the program

Here’s the code for my colorselect program. I guess it requires libgtk2.0. Compile with "gcc colorselect.c -o colorselect pkg-config --cflags --libs gtk+-2.0"[code]#include <gtk/gtk.h>

GdkColor ncolor;

static gboolean delete_event(GtkWidget *widget, GdkEvent *event, gpointer data) {
gtk_main_quit();
return TRUE;
}

static gboolean apply(GtkWidget *widget, GdkEvent *event, gpointer data) {
printf("%02x%02x%02x", ncolor.red / 256, ncolor.green / 256, ncolor.blue / 256);
delete_event(widget, event, data);
}

static void color_changed_cb(GtkWidget *widget, GtkColorSelection *colorselect) {
gtk_color_selection_get_current_color (colorselect, &ncolor);
}

int main(int argc, char *argv[]) {
GtkWidget *window;
GtkWidget *colorselect;
GtkWidget *vbox;
GtkWidget *hbuttonbox;
GtkWidget *btApply;

gtk_init(&argc, &argv);

window = gtk_window_new(GTK_WINDOW_TOPLEVEL); //create the window
gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
gtk_window_set_title (GTK_WINDOW (window), "Color Select");

vbox = gtk_vbox_new(FALSE, 5); //create a vertical box
gtk_widget_show(vbox);
gtk_container_add(GTK_CONTAINER(window), vbox); //add vbox to the window
gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); //put a 5p border around the vbox

colorselect = gtk_color_selection_new(); //create a color selection widget
gtk_widget_show(colorselect);
gtk_color_selection_set_current_color(GTK_COLOR_SELECTION(colorselect), &ncolor);
gtk_color_selection_set_has_opacity_control (GTK_COLOR_SELECTION(colorselect), FALSE);
gtk_color_selection_set_has_palette (GTK_COLOR_SELECTION(colorselect), TRUE);
gtk_box_pack_start(GTK_BOX(vbox), colorselect, TRUE, TRUE, 0); //put colorselect in the vertical box

hbuttonbox = gtk_hbutton_box_new(); //create a horizontal box
gtk_widget_show(hbuttonbox);
gtk_box_pack_start(GTK_BOX(vbox), hbuttonbox, TRUE, TRUE, 0); //put the horizontal box in the vertical box
gtk_container_set_border_width (GTK_CONTAINER (hbuttonbox), 5);
gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox), GTK_BUTTONBOX_END);
gtk_box_set_spacing (GTK_BOX (hbuttonbox), 5);

btApply = gtk_button_new_from_stock ("gtk-apply"); //create an apply button
gtk_widget_show (btApply);
gtk_container_add (GTK_CONTAINER (hbuttonbox), btApply); //put the apply button in the horizontal box
GTK_WIDGET_SET_FLAGS (btApply, GTK_CAN_DEFAULT);

g_signal_connect ((gpointer)btApply, "clicked", G_CALLBACK(apply), NULL);
g_signal_connect (G_OBJECT(colorselect), "color_changed", G_CALLBACK(color_changed_cb), (gpointer)colorselect);
g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(apply), NULL);

gtk_widget_show(window);

gtk_main();

return 0;

}
[/code]

Actually, I wanted to do excatly the same as you: select a color from a colorchooser to modify window border colors (i don’t have title bar to my windows…). I did not find any program (among stuff like zenity) to display a colorchooser, and the only GUI language I know is Sun’s java swing (teaching, teaching…), which really did not suit this purpose. I had started to see if a script using wxwindow binding in python couldn’t do the trick (my office mate teach python…).

Thanks for the code.

Because when you run it from within fvwm, the PATH env variable is not used.

– Thomas Adam.

Do you think you could add a cancel button which discards the window and prints nothing (or trap closing the window without pressing cancel)? I’ll try to patch it myself, but I’m new to gtk.

Ok… I managed to do it.

Is that why even relative paths ("./colorselect") don’t work? I’d have thought it would at least know its working directory.

I made some changes to colorselect. There’s now command line parsing allowing you to pass in a base color and suppress output in case, uh, you just want to look up a color. The “Apply” button (or “OK” if --quiet is on) is now the default button. Some very minor refactoring was also done because I’m anal retentive. Now I just need some way of reading in and saving colorsets from my config…

[code]#include <gtk/gtk.h>

GdkColor ncolor;
GdkColor ocolor;
gboolean quiet;
gboolean revertable;

static gboolean delete_event(GtkWidget *widget, GdkEvent *event, gpointer data) {
gtk_main_quit();
return TRUE;
}

static gboolean cancel(GtkWidget *widget, GdkEvent *event, gpointer data) {
if (!quiet) printf("%02x%02x%02x", ocolor.red / 256, ocolor.green / 256, ocolor.blue / 256);
delete_event(widget, event, data);
}

static gboolean apply(GtkWidget *widget, GdkEvent *event, gpointer data) {
if (!quiet) printf("%02x%02x%02x", ncolor.red / 256, ncolor.green / 256, ncolor.blue / 256);
delete_event(widget, event, data);
}

static void color_changed_cb(GtkWidget *widget, GtkColorSelection *colorselect) {
gtk_color_selection_get_current_color(colorselect, &ncolor);
}

static void printHelp() {
printf(“Usage: colorselect [hex value]\n\n”);
printf(“Available options:\n”);
printf("\t-h,–help\tthis help\n");
printf("\t-q,–quiet\tdo not output a color value\n");
printf("\t-v,–version\tshow program version\n");
printf("\nHex value is a 6 digit RGB value.\n");
}

static gboolean parseHex(char *argv) {
int i;

for (i = 0; i < 6; i++) {
	if (argv[i]=='\0')
		return FALSE;
	if (argv[i] > 0x29 && argv[i] < 0x40 ) //if 0 to 9
		argv[i] = argv[i] & 0x0f; //convert to int
	else if (argv[i] >='a' && argv[i] <= 'f') //if a to f
		argv[i] = (argv[i] & 0x0f) + 9; //convert to int
	else if (argv[i] >='A' && argv[i] <= 'F') //if A to F
		argv[i] = (argv[i] & 0x0f) + 9; //convert to int
	else return FALSE;
}

ocolor.red = (argv[0] * 16 + argv[1]) * 257;
ocolor.green = (argv[2] * 16 + argv[3]) * 257;
ocolor.blue = (argv[4] * 16 + argv[5]) * 257;

return TRUE;

}

static gboolean parseArgs(int argc, char *argv[]) {
int i;

if (argc > 1) {
	for (i = 1; i < argc; i++) {
		if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
			printHelp();
			return FALSE;
		} else if (!strcmp(argv[i], "-q") || !strcmp(argv[i], "--quiet")) {
			quiet = TRUE;
		} else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
			printf("colorselect, version 1.0\n");
			return FALSE;
		} else {
			if (parseHex(argv[i])) {
				revertable = TRUE;
			} else{
				printHelp();
				return FALSE;
			}
		}
	}
}

}

int main(int argc, char *argv[]) {
GtkWidget *window;
GtkWidget *colorselect;
GtkWidget *vbox;
GtkWidget *hbuttonbox;
GtkWidget *btCancel;
GtkWidget *btApply;

quiet = FALSE;
revertable = FALSE;
if (!parseArgs(argc, argv)) return 0;
ncolor = ocolor;

gtk_init(&argc, &argv);

window = gtk_window_new(GTK_WINDOW_TOPLEVEL); //create the window
gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
gtk_window_set_title(GTK_WINDOW(window), "Color Select");

vbox = gtk_vbox_new(FALSE, 5); //create a vertical box
gtk_container_add(GTK_CONTAINER(window), vbox); //add vbox to the window
gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); //put a 5p border around the vbox
gtk_widget_show(vbox);

colorselect = gtk_color_selection_new(); //create a color selection widget
gtk_color_selection_set_current_color(GTK_COLOR_SELECTION(colorselect), &ocolor);
gtk_color_selection_set_has_opacity_control(GTK_COLOR_SELECTION(colorselect), FALSE);
gtk_color_selection_set_has_palette(GTK_COLOR_SELECTION(colorselect), TRUE);
gtk_box_pack_start(GTK_BOX(vbox), colorselect, TRUE, TRUE, 0); //put colorselect in the vertical box
gtk_widget_show(colorselect);

hbuttonbox = gtk_hbutton_box_new(); //create a horizontal box
gtk_box_pack_start(GTK_BOX(vbox), hbuttonbox, TRUE, TRUE, 0); //put the horizontal box in the vertical box
gtk_container_set_border_width(GTK_CONTAINER(hbuttonbox), 5);
gtk_button_box_set_layout(GTK_BUTTON_BOX(hbuttonbox), GTK_BUTTONBOX_END);
gtk_box_set_spacing(GTK_BOX(hbuttonbox), 5);
gtk_widget_show(hbuttonbox);

btCancel = gtk_button_new_from_stock("gtk-cancel"); //create a cancel button
gtk_container_add(GTK_CONTAINER(hbuttonbox), btCancel); //put the cancel button in the horizontal box
if (revertable && !quiet) gtk_widget_show(btCancel);

if (quiet) btApply = gtk_button_new_from_stock("gtk-ok"); //create an apply button
else btApply = gtk_button_new_from_stock("gtk-apply"); //create an apply button
gtk_container_add(GTK_CONTAINER(hbuttonbox), btApply); //put the apply button in the horizontal box
GTK_WIDGET_SET_FLAGS(btApply, GTK_CAN_DEFAULT);
gtk_widget_grab_default(btApply); //make this button the default
gtk_widget_show(btApply);

g_signal_connect((gpointer)btCancel, "clicked", G_CALLBACK(cancel), NULL);
g_signal_connect((gpointer)btApply, "clicked", G_CALLBACK(apply), NULL);
g_signal_connect(G_OBJECT(colorselect), "color_changed", G_CALLBACK(color_changed_cb), (gpointer)colorselect);
if (revertable) g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(cancel), NULL);
else g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(apply), NULL);

gtk_widget_show(window);

gtk_main();

return 0;

}
[/code]

Is there a way to get the current bg or fg color from a Colorset, or do I have to store it somewhere (using Setenv ?) ?

Maybe the internal:

$[fg.cs<n>]
$[bg.cs<n>]
$[hilight.cs<n>]
$[shadow.cs<n>]

variables will help you there.

– Thomas Adam.