argolance | Bonjour,
Je connais un peu le code gtkdialog3, qui me permet modestement de créer/modifier des scripts simples pour le développement d'une distribution LINUX à laquelle je collabore: Toutou LINUX FAT version RELOADED. Parmi les utilitaires, il en est un, nommé "fbxkb", qui permet d'afficher et changer la disposition du clavier, d'un simple clic gauche sur une icône-drapeau située dans la barre des tâches. Un clic droit sur cette icône affiche un menu contextuel donnant accès à une fenêtre d'information (genre A propos) ainsi qu'à un bouton pour quitter l'application.
Je trouverais bien pratique qu'une entrée supplémentaire de ce menu donne directement accès à une application, (en l'occurrence, au Gestionnaire de configuration avancée du clavier Xkb Config Manager, dont fbxkb est une sorte d'extension), sans avoir donc à passer par un raccourci dans le menu ou sur le bureau.
Ce que j'aimerais obtenir:
Le problème c'est que je ne sais pas du tout comment y parvenir. Pour un habitué de ce langage (gtk C, C++?), je suppose que ce n'est pas bien sorcier, voire basique et évident (?) de modifier le code ci-dessous pour ajouter l'entrée voulue au menu contextuel de l'icône de la barre des taches: Code :
- #include <stdlib.h>
- #include <stdio.h>
- #include <ctype.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <unistd.h>
- #include <errno.h>
- #include <locale.h>
- #include <string.h>
- #include <signal.h>
- #include <X11/Xlib.h>
- #include <gtk/gtk.h>
- #include <gdk/gdk.h>
- #include <X11/XKBlib.h>
- #include "config.h"
- #include "eggtrayicon.h"
- #include "version.h"
- static gchar version[] = VERSION;
- //#define DEBUG
- #include "dbg.h"
- /******************************************************************
- * TYPEDEFS *
- ******************************************************************/
- typedef struct _kbd_info {
- gchar *sym;
- gchar *name;
- GdkPixbuf *flag;
- } kbd_info;
- #define IMGPREFIX PREFIX "/share/fbxkb/images/"
- /******************************************************************
- * GLOBAL VARSIABLES *
- ******************************************************************/
- /* X11 common stuff */
- static Atom a_XKB_RULES_NAMES;
- static Display *dpy;
- static int xkb_event_type;
- /* internal state mashine */
- static int cur_group;
- static int ngroups;
- static GHashTable *sym2pix;
- static kbd_info group2info[XkbNumKbdGroups];
- static GdkPixbuf *zzflag;
- static int active;
- /* gtk gui */
- static GtkWidget *flag_menu;
- static GtkWidget *app_menu;
- static GtkWidget *docklet;
- static GtkWidget *image;
- static GtkWidget *about_dialog = NULL;
- /******************************************************************
- * DECLARATION *
- ******************************************************************/
- static int init();
- static void read_kbd_description();
- static void update_flag(int no);
- static GdkFilterReturn filter( XEvent *xev, GdkEvent *event, gpointer data);
- static void Xerror_handler(Display * d, XErrorEvent * ev);
- static GdkPixbuf *sym2flag(char *sym);
- static void flag_menu_create();
- static void flag_menu_destroy();
- static void flag_menu_activated(GtkWidget *widget, gpointer data);
- static void app_menu_create();
- static void app_menu_about(GtkWidget *widget, gpointer data);
- static void app_menu_exit(GtkWidget *widget, gpointer data);
- static int docklet_create();
- static int create_all();
- /******************************************************************
- * CODE *
- ******************************************************************/
- /******************************************************************
- * gtk gui *
- ******************************************************************/
- static void
- flag_menu_create()
- {
- int i;
- GdkPixbuf *flag;
- GtkWidget *mi, *img;
- //static GString *s = NULL;;
-
- ENTER;
- flag_menu = gtk_menu_new();
- for (i = 0; i < ngroups; i++) {
- mi = gtk_image_menu_item_new_with_label(
- group2info.name ? group2info[i].name : group2info[i].sym);
- g_signal_connect(G_OBJECT(mi), "activate", (GCallback)flag_menu_activated, GINT_TO_POINTER(i));
- gtk_menu_shell_append (GTK_MENU_SHELL (flag_menu), mi);
- gtk_widget_show (mi);
- flag = sym2flag(group2info[i].sym);
- img = gtk_image_new_from_pixbuf(flag);
- gtk_widget_show(img);
- gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mi), img);
- }
- RET();
- }
- static void
- flag_menu_destroy()
- {
- if (flag_menu) {
- gtk_widget_destroy(flag_menu);
- flag_menu = NULL;
- }
- }
- static void
- flag_menu_activated(GtkWidget *widget, gpointer data)
- {
- int i;
- ENTER;
- i = GPOINTER_TO_INT(data);
- DBG("asking %d group\n", i);
- XkbLockGroup(dpy, XkbUseCoreKbd, i);
- RET();
- }
- static void
- app_menu_create()
- {
- GtkWidget *mi;
-
- ENTER;
- app_menu = gtk_menu_new();
- mi = gtk_image_menu_item_new_from_stock(GTK_STOCK_DIALOG_INFO, NULL);
- g_signal_connect(G_OBJECT(mi), "activate", (GCallback)app_menu_about, NULL);
- gtk_menu_shell_append (GTK_MENU_SHELL (app_menu), mi);
- gtk_widget_show (mi);
-
- mi = gtk_menu_item_new ();
- gtk_widget_show (mi);
- gtk_menu_shell_append (GTK_MENU_SHELL (app_menu), mi);
- gtk_widget_set_sensitive (mi, FALSE);
- mi = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, NULL);
- g_signal_connect(G_OBJECT(mi), "activate", (GCallback)app_menu_exit, NULL);
- gtk_menu_shell_append (GTK_MENU_SHELL (app_menu), mi);
- gtk_widget_show (mi);
- RET();
- }
- static void
- app_menu_about(GtkWidget *widget, gpointer data)
- {
- ENTER;
- if (!about_dialog) {
- about_dialog = gtk_message_dialog_new (NULL,
- GTK_DIALOG_DESTROY_WITH_PARENT,
- GTK_MESSAGE_INFO,
- GTK_BUTTONS_CLOSE,
- "fbxkb %s\nX11 Keyboard switcher\nAuthor: Anatoly Asviyan <aanatoly@users.sf.net>", version);
- /* Destroy the dialog when the user responds to it (e.g. clicks a button) */
- g_signal_connect_swapped (about_dialog, "response",
- G_CALLBACK (gtk_widget_hide),
- about_dialog);
- }
- gtk_widget_show (about_dialog);
- RET();
- }
- static void
- app_menu_exit(GtkWidget *widget, gpointer data)
- {
- ENTER;
- exit(0);
- RET();
- }
- static void docklet_embedded(GtkWidget *widget, void *data)
- {
- ENTER;
- RET();
- }
- static void docklet_destroyed(GtkWidget *widget, void *data)
- {
- ENTER;
- //g_object_unref(G_OBJECT(docklet));
- docklet = NULL;
- g_idle_add(create_all, NULL);
- RET();
- }
- void docklet_clicked(GtkWidget *button, GdkEventButton *event, void *data)
- {
- //GtkWidget *menu;
- ENTER;
- if (event->type != GDK_BUTTON_PRESS)
- RET();
- if (event->button == 1) {
- int no;
- no = (cur_group + 1) % ngroups;
- DBG("no=%d\n", no);
- XkbLockGroup(dpy, XkbUseCoreKbd, no);
- } else if (event->button == 2) {
- gtk_menu_popup(GTK_MENU(flag_menu), NULL, NULL, NULL, NULL, event->button, event->time);
- } else if (event->button == 3) {
- gtk_menu_popup(GTK_MENU(app_menu), NULL, NULL, NULL, NULL, event->button, event->time);
- }
- RET();
- }
- static int
- docklet_create()
- {
- GtkWidget *box;
-
- ENTER;
- docklet = (GtkWidget*)egg_tray_icon_new("fbxkb" );
- box = gtk_event_box_new();
- image = gtk_image_new();
- //image = gtk_image_new();
- g_signal_connect(G_OBJECT(docklet), "embedded", G_CALLBACK(docklet_embedded), NULL);
- g_signal_connect(G_OBJECT(docklet), "destroy", G_CALLBACK(docklet_destroyed), NULL);
- g_signal_connect(G_OBJECT(box), "button-press-event", G_CALLBACK(docklet_clicked), NULL);
- gtk_container_set_border_width(GTK_CONTAINER(box), 0);
-
- gtk_container_add(GTK_CONTAINER(box), image);
- gtk_container_add(GTK_CONTAINER(docklet), box);
- gtk_widget_show_all(GTK_WIDGET(docklet));
-
- RET(1);
- }
- /******************************************************************
- * internal state machine *
- ******************************************************************/
- static gboolean
- my_str_equal (gchar *a, gchar *b)
- {
- return (a[0] == b[0] && a[1] == b[1]);
- }
-
- static GdkPixbuf *
- sym2flag(char *sym)
- {
- GdkPixbuf *flag;
- static GString *s = NULL;
- char tmp[3];
-
- ENTER;
- g_assert(sym != NULL && strlen(sym) > 1);
- flag = g_hash_table_lookup(sym2pix, sym);
- if (flag)
- RET(flag);
- if (!s)
- s = g_string_new(IMGPREFIX "tt.png" );
- s->str[s->len-6] = sym[0];
- s->str[s->len-5] = sym[1];
- flag = gdk_pixbuf_new_from_file_at_size(s->str, 24, 24, NULL);
- if (!flag)
- RET(zzflag);
- tmp[0] = sym[0];
- tmp[1] = sym[1];
- tmp[2] = 0;
- g_hash_table_insert(sym2pix, tmp, flag);
- RET(flag);
- }
- static void
- read_kbd_description()
- {
- unsigned int mask;
- XkbDescRec *kbd_desc_ptr;
- XkbStateRec xkb_state;
- Atom sym_name_atom;
- int i;
- ENTER;
- // clean up
- cur_group = ngroups = 0;
- for (i = 0; i < XkbNumKbdGroups; i++) {
- g_free(group2info[i].sym);
- g_free(group2info[i].name);
- /*
- if (group2info[i].flag)
- g_object_unref(G_OBJECT(group2info[i].flag));
- */
- }
- bzero(group2info, sizeof(group2info));
- // get kbd info
- mask = XkbControlsMask | XkbServerMapMask;
- kbd_desc_ptr = XkbAllocKeyboard();
- if (!kbd_desc_ptr) {
- ERR("can't alloc kbd info\n" );
- goto out_us;
- }
- kbd_desc_ptr->dpy = dpy;
- if (XkbGetControls(dpy, XkbAllControlsMask, kbd_desc_ptr) != Success) {
- ERR("can't get Xkb controls\n" );
- goto out;
- }
- ngroups = kbd_desc_ptr->ctrls->num_groups;
- if (ngroups < 1)
- goto out;
- if (XkbGetState(dpy, XkbUseCoreKbd, &xkb_state) != Success) {
- ERR("can't get Xkb state\n" );
- goto out;
- }
- cur_group = xkb_state.group;
- DBG("cur_group = %d ngroups = %d\n", cur_group, ngroups);
- g_assert(cur_group < ngroups);
-
- if (XkbGetNames(dpy, XkbSymbolsNameMask, kbd_desc_ptr) != Success) {
- ERR("can't get Xkb symbol description\n" );
- goto out;
- }
- if (XkbGetNames(dpy, XkbGroupNamesMask, kbd_desc_ptr) != Success)
- ERR("Failed to get keyboard description\n" );
- g_assert(kbd_desc_ptr->names);
- sym_name_atom = kbd_desc_ptr->names->symbols;
- // parse kbd info
- if (sym_name_atom != None) {
- char *sym_name, *tmp, *tok;
- int no;
-
- sym_name = XGetAtomName(dpy, sym_name_atom);
- if (!sym_name)
- goto out;
- /* to know how sym_name might look like do this:
- * % xlsatoms | grep pc
- * 150 pc/pc(pc101)+pc/us+pc/ru(phonetic):2+group(shift_toggle)
- * 470 pc(pc105)+us+ru(phonetic):2+il(phonetic):3+group(shifts_toggle)+group(switch)
- */
- DBG("sym_name=%s\n", sym_name);
- for (tok = strtok(sym_name, "+" ); tok; tok = strtok(NULL, "+" )) {
- DBG("tok=%s\n", tok);
- tmp = strchr(tok, ':');
- if (tmp) {
- if (sscanf(tmp+1, "%d", &no) != 1)
- ERR("can't read kbd number\n" );
- no--;
- *tmp = 0;
- } else {
- no = 0;
- }
- for (tmp = tok; isalpha(*tmp); tmp++);
- *tmp = 0;
- DBG("map=%s no=%d\n", tok, no);
- if (!strcmp(tok, "pc" ) || !strcmp(tok, "group" ))
- continue;
-
- g_assert((no >= 0) && (no < ngroups));
- if (group2info[no].sym != NULL) {
- ERR("xkb group #%d is already defined\n", no);
- }
- group2info[no].sym = g_strdup(tok);
- group2info[no].flag = sym2flag(tok);
- group2info[no].name = XGetAtomName(dpy, kbd_desc_ptr->names->groups[no]);
- }
- XFree(sym_name);
- }
- out:
- XkbFreeKeyboard(kbd_desc_ptr, 0, True);
- // sanity check: group numbering must be continous
- for (i = 0; (i < XkbNumKbdGroups) && (group2info[i].sym != NULL); i++);
- if (i != ngroups) {
- ERR("kbd group numbering is not continous\n" );
- ERR("run 'xlsatoms | grep pc' to know what hapends\n" );
- exit(1);
- }
- out_us:
- //if no groups were defined just add default 'us' kbd group
- if (!ngroups) {
- ngroups = 1;
- cur_group = 0;
- group2info[0].sym = g_strdup("us" );
- group2info[0].flag = sym2flag("us" );
- group2info[0].name = NULL;
- ERR("no kbd groups defined. adding default 'us' group\n" );
- }
- RET();
- }
- static void update_flag(int no)
- {
- kbd_info *k = &group2info[no];
- ENTER;
- g_assert(k != NULL);
- DBG("k->sym=%s\n", k->sym);
- gtk_image_set_from_pixbuf(GTK_IMAGE(image), k->flag);
- RET();
- }
- static GdkFilterReturn
- filter( XEvent *xev, GdkEvent *event, gpointer data)
- {
- ENTER;
- if (!active)
- RET(GDK_FILTER_CONTINUE);
-
- if (xev->type == xkb_event_type) {
- XkbEvent *xkbev = (XkbEvent *) xev;
- DBG("XkbTypeEvent %d \n", xkbev->any.xkb_type);
- if (xkbev->any.xkb_type == XkbStateNotify) {
- DBG("XkbStateNotify: %d\n", xkbev->state.group);
- cur_group = xkbev->state.group;
- if (cur_group < ngroups)
- update_flag(cur_group);
- } else if (xkbev->any.xkb_type == XkbNewKeyboardNotify) {
- DBG("XkbNewKeyboardNotify\n" );
- read_kbd_description();
- //cur_group = 0;
- update_flag(cur_group);
- flag_menu_destroy();
- flag_menu_create();
- }
- RET(GDK_FILTER_REMOVE);
- }
- RET(GDK_FILTER_CONTINUE);
- }
- static int
- init()
- {
- int dummy;
- ENTER;
- sym2pix = g_hash_table_new(g_str_hash, (GEqualFunc) my_str_equal);
- dpy = GDK_DISPLAY();
- a_XKB_RULES_NAMES = XInternAtom(dpy, "_XKB_RULES_NAMES", False);
- if (a_XKB_RULES_NAMES == None)
- ERR("_XKB_RULES_NAMES - can't get this atom\n" );
- if (!XkbQueryExtension(dpy, &dummy, &xkb_event_type, &dummy, &dummy, &dummy))
- RET(0);
- DBG("xkb_event_type=%d\n", xkb_event_type);
- XkbSelectEventDetails(dpy, XkbUseCoreKbd, XkbStateNotify,
- XkbAllStateComponentsMask, XkbGroupStateMask);
- gdk_window_add_filter(NULL, (GdkFilterFunc)filter, NULL);
- zzflag = gdk_pixbuf_new_from_file_at_size(IMGPREFIX "zz.png", 24, 24, NULL);
- RET(1);
- }
- #if 0
- static void
- app_menu_destroy()
- {
- ENTER;
- if (app_menu) {
- gtk_widget_destroy(app_menu);
- app_menu = NULL;
- }
- RET();
- }
- static void
- destroy_all()
- {
- active = 0;
- gdk_window_remove_filter(NULL, (GdkFilterFunc)filter, NULL);
- XkbSelectEventDetails(dpy, XkbUseCoreKbd, XkbStateNotify,
- XkbAllStateComponentsMask, 0UL);
- flag_menu_destroy();
- app_menu_destroy();
- }
- #endif
- static int
- create_all()
- {
- ENTER;
- read_kbd_description();
- docklet_create();
- flag_menu_create();
- app_menu_create();
- update_flag(cur_group);
- active = 1;
- RET(FALSE);// FALSE will remove us from idle func
- }
- int
- main(int argc, char *argv[], char *env[])
- {
- ENTER;
- setlocale(LC_CTYPE, "" );
- gtk_set_locale();
- gtk_init(&argc, &argv);
- XSetLocaleModifiers("" );
- XSetErrorHandler((XErrorHandler) Xerror_handler);
- if (!init())
- ERR("can't init. exiting\n" );
- create_all();
- gtk_main ();
- RET(0);
- }
- /********************************************************************/
- void
- Xerror_handler(Display * d, XErrorEvent * ev)
- {
- char buf[256];
- ENTER;
- XGetErrorText(GDK_DISPLAY(), ev->error_code, buf, 256);
- ERR( "fbxkb : X error: %s\n", buf);
- RET();
- }
|
L'application a lancer est:
Pas ce chemin à préciser, vu qu'il peut varier d'un système à l'autre et qu'un raccourci vers cette application se trouve dans le dossier /usr/bin.
J'en demande beaucoup et sous estime peut-être le travail de codage que ça demande?
... Mais qui ne risque rien n'a rien!
Note: Le nom de l'auteur de la modification apparaitrait évidemment, de droit, dans la fenêtre d'information où figure déjà celui de l'auteur du script original[i] (Anatoly Asviyan)
Merci de votre aide éventuelle!
Cordialement. |