e16-keyedit/viewer.c

1248 lines
34 KiB
C

#include "config.h"
#include <gtk/gtk.h>
#include <ctype.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <X11/Xlib.h>
#include <X11/XKBlib.h>
#include <gdk/gdkx.h>
#include <unistd.h>
#include "e16keyedit.h"
#if USE_GTK == 3
#define USE_GTK_TREEVIEW 1
#else
#define USE_GTK_TREEVIEW 1
#endif
#if !USE_GTK_TREEVIEW
#define ENABLE_SORTING 1
#endif
#define DEBUG 0
#define VER(maj, min, mic) (10000 * (maj) + 100 * (min) + (mic))
GtkAccelGroup *accel_group;
static GtkWidget *clist;
static GtkWidget *act_key;
static GtkWidget *act_params;
static GtkWidget *act_mod;
static GtkWidget *act_clist;
static gchar *e_ipc_msg = NULL;
static char dont_update = 0;
static int last_row = 0;
static int real_rows = 0;
typedef struct
{
const char *name_short;
const char *name_long;
} Modifier;
typedef struct
{
const char *text;
gchar param_tpe;
const char *params;
const char *command;
} ActionOpt;
/* *INDENT-OFF* */
static const Modifier modifiers[] = {
{"-", ""},
{"C", "CTRL"},
{"S", "SHIFT"},
{"A", "ALT"},
{"CS", "CTRL+SHIFT"},
{"CA", "CTRL+ALT"},
{"SA", "ALT+SHIFT"},
{"CSA", "CTRL+ALT+SHIFT"},
{"2", "MOD2"},
{"3", "MOD3"},
{"4", "MOD4"},
{"5", "MOD5"},
{"C2", "MOD2+CTRL"},
{"S2", "MOD2+SHIFT"},
{"A2", "MOD2+ALT"},
{"C4", "MOD4+CTRL"},
{"S4", "MOD4+SHIFT"},
{"A4", "MOD4+ALT"},
{"CS4", "MOD4+CTRL+SHIFT"},
{"C5", "MOD5+CTRL"},
{"S5", "MOD5+SHIFT"},
{"A5", "MOD5+ALT"},
{"CS5", "MOD5+CTRL+SHIFT"},
};
#define N_MODIFIERS (sizeof(modifiers)/sizeof(Modifier))
#define MOD_TEXT(mod) modifiers[mod].name_long
static const ActionOpt actions_default[] = {
{"Run command", 1, NULL, "exec "},
{"Restart Enlightenment", 0, "restart", "restart"},
{"Exit Enlightenment", 0, NULL, "exit"},
{"Goto Next Desktop", 0, NULL, "desk next"},
{"Goto Previous Deskop", 0, NULL, "desk prev"},
{"Goto Desktop", 2, NULL, "desk goto "},
{"Raise Desktop", 0, NULL, "desk raise"},
{"Lower Desktop", 0, NULL, "desk lower"},
{"Reset Desktop In Place", 0, NULL, "desk this"},
{"Cleanup Windows", 0, NULL, "misc arrange size"},
{"Move mouse pointer to next screen", 0, NULL, "warp screen"},
{"Move mouse pointer to left", 0, "-1 0", "warp rel -1 0"},
{"Move mouse pointer to right", 0, "1 0", "warp rel 1 0"},
{"Move mouse pointer up", 0, "0 -1", "warp rel 0 -1"},
{"Move mouse pointer down", 0, "0 1", "warp rel 0 1"},
{"Move mouse pointer by [X Y]", 3, NULL, "warp rel "},
{"Goto Desktop area [X Y]", 3, NULL, "area goto"},
{"Move to Desktop area on the left", 0, "-1 0", "area move -1 0"},
{"Move to Desktop area on the right", 0, "1 0", "area move 1 0"},
{"Move to Desktop area above", 0, "0 -1", "area move 0 -1"},
{"Move to Desktop area below", 0, "0 1", "area move 0 1"},
{"Raise Window", 0, NULL, "wop * raise"},
{"Lower Window", 0, NULL, "wop * lower"},
{"Close Window", 0, NULL, "wop * close"},
{"Annihilate Window", 0, NULL, "wop * kill"},
{"Stick / Unstick Window", 0, NULL, "wop * stick"},
{"Iconify Window", 0, NULL, "wop * iconify"},
{"Shade / Unshade Window", 0, NULL, "wop * shade"},
{"Maximise Height of Window", 0, "conservative", "wop * th conservative"},
{"Maximise Height of Window to available space", 0, "available", "wop * th available"},
{"Maximise Height of Window to whole screen", 0, NULL, "wop * th"},
{"Maximise Width of Window", 0, "conservative", "wop * tw conservative"},
{"Maximise Width of Window to available space", 0, "available", "wop * tw available"},
{"Maximise Width of Window to whole screen", 0, NULL, "wop * tw"},
{"Maximise Size of Window", 0, "conservative", "wop * ts conservative"},
{"Maximise Size of Window to available space", 0, "available", "wop * ts available"},
{"Maximise Size of Window to whole screen", 0, NULL, "wop * ts"},
{"Toggle Window fullscreen state", 0, NULL, "wop * fullscreen"},
{"Toggle Window zoom state", 0, NULL, "wop * zoom"},
{"Send window to next desktop", 0, NULL, "wop * desk next"},
{"Send window to previous desktop", 0, NULL, "wop * desk prev"},
{"Switch focus to next window", 0, NULL, "focus next"},
{"Switch focus to previous window", 0, NULL, "focus prev"},
{"Glue / Unglue Window to Desktop screen", 0, NULL, "wop * no_user_move"},
{"Set Window layer to On Top", 0, "20", "wop * layer 20"},
{"Set Window layer to Above", 0, "6", "wop * layer 6"},
{"Set Window layer to Normal", 0, "4", "wop * layer 4"},
{"Set Window layer to Below", 0, "2", "wop * layer 2"},
{"Set Window layer", 2, NULL, "wop * layer "},
{"Move Window to area on left", 0, "-1 0", "wop * area move -1 0"},
{"Move Window to area on right", 0, "1 0", "wop * area move 1 0"},
{"Move Window to area above", 0, "0 -1", "wop * area move 0 -1"},
{"Move Window to area below", 0, "0 1", "wop * area move 0 1"},
{"Move Window by area [X Y]", 3, NULL, "wop * area "},
{"Set Window border style to the Default", 0, "DEFAULT", "wop * border DEFAULT"},
{"Set Window border style to the Borderless", 0, "BORDERLESS", "wop * border BORDERLESS"},
{"Forget everything about Window", 0, "none", "wop * snap none"},
{"Remember all Window settings", 0, NULL, "wop * snap all"},
{"Remember Window Border", 0, "border", "wop * snap border"},
{"Remember Window Desktop", 0, "desktop", "wop * snap desktop"},
{"Remember Window Desktop Area", 0, "area", "wop * snap area"},
{"Remember Window Size", 0, "size", "wop * snap size"},
{"Remember Window Location", 0, "location", "wop * snap location"},
{"Remember Window Layer", 0, "layer", "wop * snap layer"},
{"Remember Window Stickyness", 0, "sticky", "wop * snap sticky"},
{"Remember Window Shadedness", 0, "shade", "wop * snap shade"},
{"Show Root Menu", 0, "ROOT_2", "menus show ROOT_2"},
{"Show Winops Menu", 0, "WINOPS_MENU", "menus show WINOPS_MENU"},
{"Show Named Menu", 1, NULL, "menus show "},
{NULL, 0, NULL, NULL}
};
/* *INDENT-ON* */
static const ActionOpt *actions = NULL;
static unsigned int action_count = sizeof(actions_default) / sizeof(ActionOpt);
static unsigned int *action_index_to_row = NULL;
static unsigned int *action_row_to_index = NULL;
static int
match_action_by_binding(const char *params)
{
int k, len;
for (k = 0; actions[k].text; k++)
{
len = strlen(actions[k].command);
if (strncmp(actions[k].command, params, len))
continue;
return k;
}
return -1;
}
static int
match_action_by_selection(const char *text)
{
int k;
for (k = 0; actions[k].text; k++)
{
if (strcmp(text, actions[k].text))
continue;
return k;
}
return -1;
}
static unsigned
mod_short_to_index(const char *name_short)
{
unsigned int k;
for (k = 0; k < N_MODIFIERS; k++)
{
if (!strcmp(name_short, modifiers[k].name_short))
return k;
}
return 0; /* Discard modifier */
}
#if USE_GTK_TREEVIEW
static int
clist_sel_row_get(GtkTreeSelection * sel)
{
int row, *rows;
GtkTreeIter iter;
GtkTreeModel *model;
GtkTreePath *path;
row = -1;
if (gtk_tree_selection_get_selected(sel, &model, &iter))
{
path = gtk_tree_model_get_path(model, &iter);
rows = gtk_tree_path_get_indices(path);
row = rows[0];
}
return row;
}
#endif
static void
clist_row_current_set_value(GtkWidget * widget, int col, const char *txt)
{
#if USE_GTK_TREEVIEW
GtkTreeSelection *sel;
GtkTreeModel *model;
GtkTreeIter iter;
sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
if (gtk_tree_selection_get_selected(sel, &model, &iter))
gtk_list_store_set(GTK_LIST_STORE(model), &iter, col, txt, -1);
#else
gtk_clist_set_text(GTK_CLIST(widget), last_row, col, txt);
#endif
}
static void
clist_row_moveto(GtkWidget * widget, int row)
{
#if USE_GTK_TREEVIEW
GtkTreeSelection *sel;
GtkTreePath *path;
sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
path = gtk_tree_path_new_from_indices(row, -1);
gtk_tree_selection_select_path(sel, path);
gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(widget), path, NULL, FALSE, .5,
.5);
gtk_tree_path_free(path);
#else
gtk_clist_select_row(GTK_CLIST(widget), row, 0);
gtk_clist_moveto(GTK_CLIST(widget), row, 0, 0.5, 0.5);
#endif
}
static void
e_cb_key_change(GtkWidget * widget __UNUSED__, gpointer data __UNUSED__)
{
GtkWidget *win, *frame, *vbox, *label;
win = gtk_window_new(GTK_WINDOW_POPUP);
gtk_window_set_position(GTK_WINDOW(win), GTK_WIN_POS_MOUSE);
frame = gtk_frame_new(NULL);
gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT);
vbox = gtk_vbox_new(FALSE, 5);
label = gtk_label_new("Please press the key on the keyboard\n"
"you wish to modify this keyboard-shortcut\n"
"to use from now on.");
gtk_container_add(GTK_CONTAINER(win), frame);
gtk_container_add(GTK_CONTAINER(frame), vbox);
gtk_container_add(GTK_CONTAINER(vbox), label);
gtk_container_set_border_width(GTK_CONTAINER(vbox), 32);
gtk_widget_show_all(win);
while (gtk_events_pending())
gtk_main_iteration();
gdk_flush();
while (gtk_events_pending())
gtk_main_iteration();
{
char *key;
XEvent ev;
#define WIDGET_XID(widget) GDK_WINDOW_XID(gtk_widget_get_window(widget))
gdk_window_set_events(gtk_widget_get_window(win), GDK_KEY_PRESS_MASK);
XGrabKeyboard(gdk_x11_get_default_xdisplay(), WIDGET_XID(win),
False, GrabModeAsync, GrabModeAsync, CurrentTime);
XSetInputFocus(gdk_x11_get_default_xdisplay(), WIDGET_XID(win),
RevertToPointerRoot, CurrentTime);
XWindowEvent(gdk_x11_get_default_xdisplay(), WIDGET_XID(win),
KeyPressMask, &ev);
XUngrabKeyboard(gdk_x11_get_default_xdisplay(), CurrentTime);
key = XKeysymToString(XkbKeycodeToKeysym(gdk_x11_get_default_xdisplay(),
ev.xkey.keycode, 0, 0));
gtk_entry_set_text(GTK_ENTRY(act_key), key);
clist_row_current_set_value(clist, 1, key);
}
gtk_widget_destroy(win);
}
static void
e_cb_modifier(GtkWidget * widget, gpointer data __UNUSED__)
{
int i;
if (dont_update)
return;
i = gtk_combo_box_get_active(GTK_COMBO_BOX(widget));
clist_row_current_set_value(clist, 0, MOD_TEXT(i));
}
static gchar *
wait_for_ipc_msg(void)
{
e_ipc_msg = NULL;
do
{
gtk_main_iteration();
}
while (!e_ipc_msg);
return e_ipc_msg;
}
#if USE_GTK_TREEVIEW
static void
change_action(GtkTreeSelection * sel, gpointer data __UNUSED__)
#else
static void
change_action(GtkWidget * my_clist __UNUSED__, gint row, gint column __UNUSED__,
GdkEventButton * event __UNUSED__, gpointer data __UNUSED__)
#endif
{
int k;
if (dont_update)
return;
#if USE_GTK_TREEVIEW
int row;
row = clist_sel_row_get(sel);
#endif
if (row < 0)
return;
k = action_row_to_index[row];
if (actions[k].param_tpe != 0)
{
gtk_editable_set_editable(GTK_EDITABLE(act_params), TRUE);
gtk_widget_set_sensitive(act_params, TRUE);
}
else
{
gtk_editable_set_editable(GTK_EDITABLE(act_params), FALSE);
gtk_widget_set_sensitive(act_params, FALSE);
gtk_entry_set_text(GTK_ENTRY(act_params), "");
}
dont_update = 1;
if (actions[k].command)
gtk_entry_set_text(GTK_ENTRY(act_params), actions[k].command);
else
gtk_entry_set_text(GTK_ENTRY(act_params), "* Not available *");
dont_update = 0;
clist_row_current_set_value(clist, 2, actions[k].text);
clist_row_current_set_value(clist, 3,
gtk_entry_get_text(GTK_ENTRY(act_params)));
}
static char *
dupcat(char *dst, const char *src)
{
char *s;
int len1, len2;
if (!dst)
return strdup(src);
len1 = strlen(dst);
len2 = strlen(src);
s = realloc(dst, len1 + len2 + 1);
strcpy(s + len1, src);
return s;
}
static void
on_save_data(void)
{
char *buf = NULL;
buf = dupcat(buf, "ac kb set\nAclass KEYBINDINGS global\n");
#if USE_GTK_TREEVIEW
GtkTreeModel *model;
GtkTreeIter iter;
gboolean ok;
model = gtk_tree_view_get_model(GTK_TREE_VIEW(clist));
for (ok = gtk_tree_model_get_iter_first(model, &iter); ok;
ok = gtk_tree_model_iter_next(model, &iter))
#else
int i;
for (i = 0; i < real_rows; i++)
#endif
{
char tmp[1024];
char *mod, *key, *prm;
int modifier = 0;
int j;
#if USE_GTK_TREEVIEW
gtk_tree_model_get(model, &iter, 0, &mod, 1, &key, 3, &prm, -1);
#else
gtk_clist_get_text(GTK_CLIST(clist), i, 0, &mod);
gtk_clist_get_text(GTK_CLIST(clist), i, 1, &key);
gtk_clist_get_text(GTK_CLIST(clist), i, 3, &prm);
#endif
for (j = 0; j < 21; j++)
{
if (!strcmp(MOD_TEXT(j), mod))
{
modifier = j;
}
}
snprintf(tmp, sizeof(tmp), "%s %s %s %s\n", "KeyDown",
modifiers[modifier].name_short, key, prm);
buf = dupcat(buf, tmp);
}
#if DEBUG > 0
printf("%s", buf);
#endif
CommsSend(buf);
#if 0
CommsSend("save_config");
#endif
free(buf);
}
#if USE_GTK_TREEVIEW
static void
selection_made(GtkTreeSelection * sel, gpointer data __UNUSED__)
#else
static void
selection_made(GtkWidget * my_clist __UNUSED__, gint row,
gint column __UNUSED__, GdkEventButton * event __UNUSED__,
gpointer data __UNUSED__)
#endif
{
gchar *mod, *key, *act, *prm;
int i;
#if USE_GTK_TREEVIEW
int row;
row = clist_sel_row_get(sel);
#endif
if (row < 0)
return;
dont_update = 1;
#if USE_GTK_TREEVIEW
GtkTreeIter iter;
GtkTreeModel *model;
if (gtk_tree_selection_get_selected(sel, &model, &iter))
{
gtk_tree_model_get(model, &iter,
0, &mod, 1, &key, 2, &act, 3, &prm, -1);
}
#else
gtk_clist_get_text(GTK_CLIST(clist), row, 0, &mod);
gtk_clist_get_text(GTK_CLIST(clist), row, 1, &key);
gtk_clist_get_text(GTK_CLIST(clist), row, 2, &act);
gtk_clist_get_text(GTK_CLIST(clist), row, 3, &prm);
#endif
for (i = 0; i < 21; i++)
{
if (!strcmp(MOD_TEXT(i), mod))
gtk_combo_box_set_active(GTK_COMBO_BOX(act_mod), i);
}
gtk_entry_set_text(GTK_ENTRY(act_key), key);
gtk_entry_set_text(GTK_ENTRY(act_params), prm);
i = match_action_by_selection(act);
if (i < 0 || actions[i].param_tpe == 0)
{
gtk_editable_set_editable(GTK_EDITABLE(act_params), FALSE);
gtk_widget_set_sensitive(act_params, FALSE);
}
else
{
gtk_editable_set_editable(GTK_EDITABLE(act_params), TRUE);
gtk_widget_set_sensitive(act_params, TRUE);
}
#if USE_GTK_TREEVIEW
g_free(mod);
g_free(key);
g_free(act);
g_free(prm);
#endif
if (i >= 0)
{
i = action_index_to_row[i];
clist_row_moveto(act_clist, i);
}
/* printf("%s\n%s\n%s\n%s\n",mod,key,act,prm); */
last_row = row;
dont_update = 0;
}
static gchar *get_line(gchar * str, int num);
static gchar *
get_line(gchar * str, int num)
{
gchar *s1, *s2, *s;
gint i, count, l;
i = 0;
count = 0;
s1 = str;
if (*str == '\n')
i = 1;
s2 = NULL;
for (i = 0;; i++)
{
if ((str[i] == '\n') || (str[i] == 0))
{
s2 = &(str[i]);
if ((count == num) && (s2 > s1))
{
l = s2 - s1;
s = g_malloc(l + 1);
strncpy(s, s1, l);
s[l] = 0;
return s;
}
count++;
if (str[i] == 0)
return NULL;
s1 = s2 + 1;
}
}
}
#if ENABLE_SORTING
static void
on_resort_columns(GtkWidget * widget __UNUSED__, gint column,
gpointer data __UNUSED__)
{
static int order = 0;
static int last_col = 0;
gtk_clist_set_sort_column(GTK_CLIST(clist), column);
if (last_col == column)
{
if (order)
{
order = 0;
gtk_clist_set_sort_type(GTK_CLIST(clist), GTK_SORT_DESCENDING);
}
else
{
order = 1;
gtk_clist_set_sort_type(GTK_CLIST(clist), GTK_SORT_ASCENDING);
}
}
else
{
order = 1;
gtk_clist_set_sort_type(GTK_CLIST(clist), GTK_SORT_ASCENDING);
last_col = column;
}
gtk_clist_sort(GTK_CLIST(clist));
}
#endif /* ENABLE_SORTING */
static void
on_delete_row(GtkWidget * widget __UNUSED__, gpointer data __UNUSED__)
{
#if USE_GTK_TREEVIEW
GtkTreeSelection *sel;
GtkTreeIter iter;
GtkTreeModel *model;
sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(clist));
if (!gtk_tree_selection_get_selected(sel, &model, &iter))
return;
gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
#else
gtk_clist_remove(GTK_CLIST(clist), last_row);
#endif
real_rows--;
if (last_row >= real_rows)
last_row--;
clist_row_moveto(clist, last_row);
}
static void
on_create_row(GtkWidget * widget __UNUSED__, gpointer data __UNUSED__)
{
#if USE_GTK_TREEVIEW
GtkTreeModel *model;
GtkTreeIter iter;
model = gtk_tree_view_get_model(GTK_TREE_VIEW(clist));
gtk_list_store_append(GTK_LIST_STORE(model), &iter);
gtk_list_store_set(GTK_LIST_STORE(model), &iter,
0, "", 1, "", 2, "", 3, "", -1);
#else
char *stuff[4];
stuff[0] = "";
stuff[1] = "";
stuff[2] = "";
stuff[3] = "";
gtk_clist_select_row(GTK_CLIST(clist),
gtk_clist_append(GTK_CLIST(clist), stuff), 0);
#endif
last_row = real_rows++;
clist_row_moveto(clist, last_row);
}
static void
on_change_params(GtkWidget * widget, gpointer data __UNUSED__)
{
const char *txt;
if (dont_update)
return;
txt = gtk_entry_get_text(GTK_ENTRY(widget));
clist_row_current_set_value(clist, 3, txt);
}
void
on_exit_application(void)
{
exit(0);
}
static void
on_save_and_exit_application(void)
{
on_save_data();
on_exit_application();
}
static GtkWidget *
create_list_window(void)
{
GtkWidget *list_window;
GtkWidget *bigvbox;
GtkWidget *menubar;
GtkWidget *panes;
GtkWidget *scrollybit;
GtkWidget *vbox;
GtkWidget *frames;
GtkWidget *frame_vbox;
GtkWidget *table;
GtkWidget *label;
GtkWidget *entry;
GtkWidget *button;
GtkWidget *hbox;
GtkWidget *om;
GtkWidget *menu;
#if USE_GTK_TREEVIEW
GtkCellRenderer *renderer;
GtkListStore *store;
GtkTreeIter iter;
GtkTreeSelection *sel;
#endif
int i;
list_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size(GTK_WINDOW(list_window), 400, 400);
g_object_set_data(G_OBJECT(list_window), "key_editor", list_window);
gtk_widget_set_can_focus(list_window, TRUE);
gtk_widget_set_can_default(list_window, TRUE);
gtk_window_set_title(GTK_WINDOW(list_window), "E Keys Editor");
bigvbox = gtk_vbox_new(FALSE, 0);
gtk_container_add(GTK_CONTAINER(list_window), bigvbox);
menubar = gtk_menu_bar_new();
gtk_box_pack_start(GTK_BOX(bigvbox), menubar, FALSE, FALSE, 0);
menu = CreateBarSubMenu(menubar, "File");
CreateMenuItem(menu, "Save", "", "Save Current Data", on_save_data, NULL);
CreateMenuItem(menu, "Save & Quit", "",
"Save Current Data & Quit Application",
on_save_and_exit_application, NULL);
CreateMenuItem(menu, "Quit", "", "Quit Without Saving",
on_exit_application, NULL);
#if 0 /* Not implemented */
menu = CreateRightAlignBarSubMenu(menubar, "Help");
menuitem = CreateMenuItem(menu, "About", "", "About E Keybinding Editor",
NULL, "about");
menuitem = CreateMenuItem(menu, "Documentation", "",
"Read the Keybinding Editor Documentation", NULL,
"read docs");
#endif
#if USE_GTK == 3
panes = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL);
#else
panes = gtk_hpaned_new();
#endif
gtk_box_pack_start(GTK_BOX(bigvbox), panes, TRUE, TRUE, 0);
scrollybit = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollybit),
GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
gtk_paned_pack1(GTK_PANED(panes), scrollybit, TRUE, FALSE);
#if USE_GTK_TREEVIEW
clist = gtk_tree_view_new();
renderer = gtk_cell_renderer_text_new();
gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(clist),
-1, "Modifier", renderer, "text",
0, NULL);
renderer = gtk_cell_renderer_text_new();
gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(clist),
-1, "Key", renderer, "text", 1,
NULL);
renderer = gtk_cell_renderer_text_new();
gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(clist),
-1, "Action to Perform",
renderer, "text", 2, NULL);
renderer = gtk_cell_renderer_text_new();
gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(clist),
-1, "Command", renderer, "text",
3, NULL);
store = gtk_list_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
G_TYPE_STRING);
#else
clist = gtk_clist_new(4);
gtk_clist_set_column_title(GTK_CLIST(clist), 0, "Modifier");
gtk_clist_set_column_title(GTK_CLIST(clist), 1, "Key");
gtk_clist_set_column_title(GTK_CLIST(clist), 2, "Action to Perform");
gtk_clist_set_column_title(GTK_CLIST(clist), 3, "Command");
#if 0
gtk_clist_set_column_auto_resize(GTK_CLIST(clist), 0, TRUE);
gtk_clist_set_column_auto_resize(GTK_CLIST(clist), 1, TRUE);
#endif
gtk_clist_column_titles_show(GTK_CLIST(clist));
#endif
gtk_container_add(GTK_CONTAINER(scrollybit), clist);
{
char *msg, *buf;
int j, k, modifier;
char event[128], mod[128], key[128], *params;
const char *stuff[4];
int len;
CommsSend("ac kb");
msg = wait_for_ipc_msg();
i = 0;
while ((buf = get_line(msg, i++)))
{
if (strlen(buf) < 1)
break;
j = sscanf(buf, "%127s %127s %127s %n", event, mod, key, &len);
#if DEBUG > 0
printf("buf(%d): %s\n", j, buf);
#endif
if (j < 3)
goto next;
if (strcmp(event, "KeyDown"))
goto next;
params = buf + len;
#if DEBUG > 0
printf("event: %s, mod: %s, key: %s, params: %s\n",
event, mod, key, params);
#endif
modifier = mod_short_to_index(mod);
k = match_action_by_binding(params);
#if DEBUG > 1
printf("key: %s, mod: %s, act=%d, params: %s\n", key,
MOD_TEXT(modifier), k, params);
#endif
stuff[0] = MOD_TEXT(modifier);
stuff[1] = key;
stuff[2] = (k >= 0) ? actions[k].text : "* Not recognised *";
stuff[3] = params;
#if USE_GTK_TREEVIEW
gtk_list_store_append(store, &iter);
gtk_list_store_set(store, &iter,
0, stuff[0], 1, stuff[1],
2, stuff[2], 3, stuff[3], -1);
#else
gtk_clist_append(GTK_CLIST(clist), (char **)stuff);
#endif
real_rows++;
next:
g_free(buf);
}
g_free(msg);
}
#if USE_GTK_TREEVIEW
gtk_tree_view_set_model(GTK_TREE_VIEW(clist), GTK_TREE_MODEL(store));
g_object_unref(store);
sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(clist));
gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
g_signal_connect(G_OBJECT(sel), "changed", G_CALLBACK(selection_made), NULL);
#if ENABLE_SORTING
g_signal_connect(G_OBJECT(clist), "click_column", /////////////////// CRAP
G_CALLBACK(on_resort_columns), NULL);
#endif
#else
gtk_clist_columns_autosize(GTK_CLIST(clist));
g_signal_connect(G_OBJECT(clist), "select_row",
G_CALLBACK(selection_made), NULL);
g_signal_connect(G_OBJECT(clist), "click_column",
G_CALLBACK(on_resort_columns), NULL);
#endif
vbox = gtk_vbox_new(FALSE, 0);
frames = gtk_frame_new("Edit Keybinding Properties");
gtk_container_set_border_width(GTK_CONTAINER(frames), 2);
gtk_paned_pack2(GTK_PANED(panes), vbox, FALSE, FALSE);
gtk_box_pack_start(GTK_BOX(vbox), frames, TRUE, TRUE, 0);
frame_vbox = gtk_vbox_new(FALSE, 3);
gtk_container_set_border_width(GTK_CONTAINER(frame_vbox), 4);
gtk_container_add(GTK_CONTAINER(frames), frame_vbox);
#if USE_GTK == 3
table = gtk_grid_new();
gtk_grid_set_row_spacing(GTK_GRID(table), 3);
gtk_grid_set_column_spacing(GTK_GRID(table), 3);
#else
table = gtk_table_new(3, 3, FALSE);
gtk_table_set_row_spacings(GTK_TABLE(table), 3);
gtk_table_set_col_spacings(GTK_TABLE(table), 3);
#endif
gtk_box_pack_start(GTK_BOX(frame_vbox), table, FALSE, FALSE, 2);
label = gtk_label_new("Key:");
#if USE_GTK == 3
gtk_widget_set_halign(label, GTK_ALIGN_END);
gtk_grid_attach(GTK_GRID(table), label, 0, 0, 1, 1);
#else
gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1,
GTK_FILL, (GtkAttachOptions) (0), 0, 0);
#endif
label = gtk_label_new("Modifier:");
#if USE_GTK == 3
gtk_widget_set_halign(label, GTK_ALIGN_END);
gtk_grid_attach(GTK_GRID(table), label, 0, 1, 1, 1);
#else
gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2,
GTK_FILL, (GtkAttachOptions) (0), 0, 0);
#endif
label = gtk_label_new("Command:");
#if USE_GTK == 3
gtk_widget_set_halign(label, GTK_ALIGN_END);
gtk_grid_attach(GTK_GRID(table), label, 0, 2, 1, 1);
#else
gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3,
GTK_FILL, (GtkAttachOptions) (0), 0, 0);
#endif
act_key = entry = gtk_entry_new();
gtk_entry_set_max_length(GTK_ENTRY(entry), 4096);
gtk_widget_set_sensitive(entry, FALSE);
#if USE_GTK == 3
gtk_widget_set_hexpand(entry, GTK_EXPAND | GTK_FILL);
gtk_grid_attach(GTK_GRID(table), entry, 1, 0, 1, 1);
#else
gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 0, 1,
GTK_EXPAND | GTK_FILL, (GtkAttachOptions) (0), 0, 0);
#endif
button = gtk_button_new_with_label("Change");
#if USE_GTK == 3
gtk_widget_set_hexpand(button, GTK_EXPAND | GTK_FILL);
gtk_grid_attach(GTK_GRID(table), button, 2, 0, 1, 1);
#else
gtk_table_attach(GTK_TABLE(table), button, 2, 3, 0, 1,
GTK_EXPAND | GTK_FILL, (GtkAttachOptions) (0), 0, 0);
#endif
g_signal_connect(G_OBJECT(button), "clicked",
G_CALLBACK(e_cb_key_change), NULL);
act_mod = om = gtk_combo_box_text_new();
gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(om), "None");
for (i = 1; i < 21; i++)
gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(om), MOD_TEXT(i));
gtk_combo_box_set_active(GTK_COMBO_BOX(om), 0);
g_signal_connect(G_OBJECT(om), "changed", G_CALLBACK(e_cb_modifier), NULL);
#if USE_GTK == 3
gtk_widget_set_hexpand(om, GTK_EXPAND | GTK_FILL);
gtk_grid_attach(GTK_GRID(table), om, 1, 1, 2, 1);
#else
gtk_table_attach(GTK_TABLE(table), om, 1, 3, 1, 2,
GTK_EXPAND | GTK_FILL, (GtkAttachOptions) (0), 0, 0);
#endif
act_params = entry = gtk_entry_new();
gtk_entry_set_max_length(GTK_ENTRY(entry), 4096);
gtk_widget_set_sensitive(entry, FALSE);
#if USE_GTK == 3
gtk_widget_set_hexpand(entry, GTK_EXPAND | GTK_FILL);
gtk_grid_attach(GTK_GRID(table), entry, 1, 2, 2, 1);
#else
gtk_table_attach(GTK_TABLE(table), entry, 1, 3, 2, 3,
GTK_EXPAND | GTK_FILL, (GtkAttachOptions) (0), 0, 0);
#endif
g_signal_connect(G_OBJECT(entry), "changed",
G_CALLBACK(on_change_params), NULL);
scrollybit = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollybit),
GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
#if USE_GTK_TREEVIEW
act_clist = gtk_tree_view_new();
renderer = gtk_cell_renderer_text_new();
gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(act_clist),
-1, "Action Used:", renderer,
"text", 0, NULL);
store = gtk_list_store_new(1, G_TYPE_STRING);
#else
act_clist = gtk_clist_new(1);
gtk_clist_set_column_title(GTK_CLIST(act_clist), 0, "Action Used:");
gtk_clist_column_titles_show(GTK_CLIST(act_clist));
#endif
gtk_box_pack_start(GTK_BOX(frame_vbox), scrollybit, TRUE, TRUE, 0);
gtk_container_add(GTK_CONTAINER(scrollybit), act_clist);
{
const char *stuff[1];
int k, row;
action_index_to_row = calloc(action_count, sizeof(int));
action_row_to_index = calloc(action_count, sizeof(int));
for (k = row = 0; (actions[k].text); k++)
{
stuff[0] = actions[k].text;
#if USE_GTK_TREEVIEW
gtk_list_store_append(store, &iter);
gtk_list_store_set(store, &iter, 0, stuff[0], -1);
#else
gtk_clist_append(GTK_CLIST(act_clist), (char **)stuff);
#endif
action_index_to_row[k] = row;
action_row_to_index[row++] = k;
}
}
#if USE_GTK_TREEVIEW
gtk_tree_view_set_model(GTK_TREE_VIEW(act_clist), GTK_TREE_MODEL(store));
g_object_unref(store);
sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(act_clist));
gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
g_signal_connect(G_OBJECT(sel), "changed", G_CALLBACK(change_action), NULL);
#else
g_signal_connect(G_OBJECT(act_clist), "select_row",
G_CALLBACK(change_action), NULL);
#endif
hbox = gtk_hbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
button = gtk_button_new_with_label(" New Keybinding ");
gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, FALSE, 5);
g_signal_connect(G_OBJECT(button), "clicked",
G_CALLBACK(on_create_row), NULL);
button = gtk_button_new_with_label(" Delete Current Row ");
gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, FALSE, 5);
g_signal_connect(G_OBJECT(button), "clicked",
G_CALLBACK(on_delete_row), NULL);
button = gtk_button_new_with_label(" Save ");
gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, FALSE, 5);
g_signal_connect(G_OBJECT(button), "clicked",
G_CALLBACK(on_save_data), NULL);
button = gtk_button_new_with_label(" Quit ");
gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, FALSE, 5);
g_signal_connect(G_OBJECT(button), "clicked",
G_CALLBACK(on_exit_application), NULL);
clist_row_moveto(clist, 0);
return list_window;
}
static void
receive_ipc_msg(gchar * msg)
{
e_ipc_msg = g_strdup(msg);
}
static void
check_e16_version(void)
{
char *msg;
const char *s;
int ver, major, minor, micro;
ver = major = minor = micro = 0;
CommsSend("ver");
msg = wait_for_ipc_msg();
if (!msg)
goto do_check;
s = msg;
while (*s && *s != '.')
s++;
s--;
sscanf(s, "%d.%d.%d", &major, &minor, &micro);
ver = VER(major, minor, micro);
free(msg);
do_check:
if (ver < VER(1, 0, 1))
{
printf("Sorry, e16 version >= 1.0.1 is required.\n");
exit(1);
}
}
static void
load_actions(void)
{
char kbdb[1024], buf[1024], text[1024], command[1024];
const char *p;
char *s;
FILE *f;
int n, opt;
unsigned int nao;
ActionOpt *pao;
actions = actions_default;
/* FIXME - Should be fetched via IPC. */
p = getenv("EROOT");
if (!p)
p = DATADIR "/e16"; /* Default location */
snprintf(kbdb, sizeof(kbdb), "%s/config/e16keyedit.db", p);
f = fopen(kbdb, "r");
if (!f)
return;
nao = 0;
pao = NULL;
for (;;)
{
s = fgets(buf, sizeof(buf), f);
if (!s)
break;
while (isspace(*s))
s++;
if (*s == '\0' || *s == '#')
continue;
n = strlen(s);
while (n > 0 && (s[n - 1] == '\n' || s[n - 1] == '\r'))
n--;
if (n <= 0)
continue;
s[n] = '\0';
#if DEBUG > 0
printf("Got: %s\n", s);
#endif
text[0] = command[0] = '\0';
opt = -1;
n = sscanf(s, "\"%1023[^\"]\", %d, \"%1023[^\"]\"", text, &opt,
command);
if (n < 2)
{
printf("*** ERROR: %s\n", buf);
printf
("*** ERROR: Keybindings database (%s) corrupt, using defaults.\n",
kbdb);
if (pao)
free(pao);
fclose(f);
return;
}
if (!command[0])
continue;
#if DEBUG > 0
printf("n=%d t=%s o=%d c=%s\n", n, text, opt, command);
#endif
pao = realloc(pao, (nao + 1) * sizeof(ActionOpt));
memset(pao + nao, 0, sizeof(ActionOpt));
pao[nao].text = strdup(text);
pao[nao].param_tpe = opt;
pao[nao].command = strdup(command);
nao++;
}
fclose(f);
if (nao == 0)
return; /* No entries ??? */
/* Add terminator record */
pao = realloc(pao, (nao + 1) * sizeof(ActionOpt));
memset(pao + nao, 0, sizeof(ActionOpt));
actions = pao;
action_count = nao;
}
int
main(int argc, char *argv[])
{
GtkWidget *lister;
setlocale(LC_ALL, "");
gtk_init(&argc, &argv);
accel_group = gtk_accel_group_new();
if (CommsInit(receive_ipc_msg))
{
GtkWidget *win, *frame, *vbox, *label, *button;
win = gtk_window_new(GTK_WINDOW_POPUP);
gtk_window_set_position(GTK_WINDOW(win), GTK_WIN_POS_CENTER);
frame = gtk_frame_new(NULL);
gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT);
vbox = gtk_vbox_new(FALSE, 5);
button = gtk_button_new_with_label("Quit");
g_signal_connect(G_OBJECT(button), "clicked",
G_CALLBACK(on_exit_application), NULL);
label = gtk_label_new("You are not running Enlightenment\n"
"\n"
"This window manager has to be running in order\n"
"to configure it.\n" "\n");
gtk_container_add(GTK_CONTAINER(win), frame);
gtk_container_add(GTK_CONTAINER(frame), vbox);
gtk_container_set_border_width(GTK_CONTAINER(vbox), 32);
gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0);
gtk_widget_show_all(win);
gtk_main();
exit(1);
}
CommsSend("set clientname Enlightenment Keybinding Configuration Utility");
CommsSend("set version " VERSION);
#if 0
CommsSend("set author Mandrake (Geoff Harrison)");
CommsSend("set email mandrake@mandrake.net");
CommsSend("set web http://mandrake.net/");
CommsSend("set address C/O VA Linux Systems, USA");
CommsSend("set info "
"This is the Enlightenemnt KeyBindings Configuration Utility\n"
"that uses Enlightenment's IPC mechanism to configure\n"
"it remotely.");
#endif
check_e16_version();
load_actions();
lister = create_list_window();
g_signal_connect(G_OBJECT(lister), "destroy",
G_CALLBACK(on_exit_application), NULL);
g_signal_connect(G_OBJECT(lister), "delete_event",
G_CALLBACK(on_exit_application), NULL);
gtk_widget_show_all(lister);
gtk_main();
return 0;
}