#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gtk/gtk.h>
#include <libawn/awn-applet.h>
#include <libawn/awn-effects.h>
#include <libawn/awn-applet-dialog.h>
#include <libawn/awn-applet-simple.h>
#include <X11/Xlib.h> // X Window headers
#include <X11/Xutil.h> // X Window headers
#include <X11/Xresource.h> // Command line parsing and X resource manager
#include <X11/XKBlib.h> // XKB fun
typedef struct {
AwnApplet *applet;
GtkWidget *window;
GtkWidget *box;
GdkPixbuf *curIcon;
GdkPixbuf *iconFlag0;
GdkPixbuf *iconFlag1;
GdkPixbuf *iconFlag2;
GdkPixbuf *iconFlag3;
Display *dpy;
Window xkbVirtWindow;
gint iconHeight;
gboolean isRu;
gint state;
} MainIcon;
static MainIcon *app;
static gboolean switchFlag() {
GdkPixbuf *icon;
switch (app->state){
case 0:
//app->curIcon = app->iconFlag0;
//awn_applet_simple_set_icon (AWN_APPLET_SIMPLE (app->applet), app->iconFlag0);
icon = gdk_pixbuf_new_from_file_at_scale("/usr/lib/awn/applets/layoutSwitcher/icons/usflag.svg", app->iconHeight - 2, app->iconHeight - 2, FALSE, NULL);
awn_applet_simple_set_temp_icon (AWN_APPLET_SIMPLE (app->applet), icon);
break;
case 1:
//app->curIcon = app->iconFlag1;
icon = gdk_pixbuf_new_from_file_at_scale("/usr/lib/awn/applets/layoutSwitcher/icons/ruflag.svg", app->iconHeight - 2, app->iconHeight - 2, FALSE, NULL);
//awn_applet_simple_set_icon (AWN_APPLET_SIMPLE (app->applet), app->iconFlag1);
awn_applet_simple_set_temp_icon (AWN_APPLET_SIMPLE (app->applet), icon);
break;
case 2:
//awn_applet_simple_set_temp_icon (AWN_APPLET_SIMPLE (app->applet), app->iconFlag2);
break;
case 3:
//awn_applet_simple_set_temp_icon (AWN_APPLET_SIMPLE (app->applet), app->iconFlag3);
break;
default:
break;
}
return TRUE;
}
void* threadXKBloop(void* attrib) {
XrmInitialize();
int event_rtrn, error_rtrn, reason_rtrn; // for XkbOpenDisplay
app->dpy = XkbOpenDisplay(NULL, &event_rtrn, &error_rtrn, NULL, NULL, &reason_rtrn);
if (app->dpy == NULL) {
g_error ("LayoutSwitcher: Cannot open display!", NULL);
exit(EXIT_FAILURE);
}
// We would like receive the only Xkb event: XkbStateNotify. And only when XkbLockGroup happens.
if (FALSE == XkbSelectEvents(app->dpy, XkbUseCoreKbd, XkbAllEventsMask, 0)) {
g_error ("LayoutSwitcher: Cannot XkbSelectEvents. It's your problem -- not mine.!", NULL);
exit(EXIT_FAILURE);
} // Deselect all events
if (FALSE == XkbSelectEventDetails(app->dpy, XkbUseCoreKbd, XkbStateNotify, XkbAllEventsMask, XkbGroupLockMask)) {
g_error ("LayoutSwitcher: Cannot XkbSelectEventDetails. It's your problem -- not mine.!", NULL);
exit(EXIT_FAILURE);
} // Select XkbStateNotify/XkbgroupLock
// Create our virtual window
int scr = DefaultScreen(app->dpy);
Window root = RootWindow(app->dpy, scr);
app->xkbVirtWindow = XCreateSimpleWindow(app->dpy, root, 0, 0, 512, 512, 0, 10L, 20L);
XStoreName(app->dpy, app->xkbVirtWindow, "switchLayoutGKV");
// We want to recive special calls from main loop
XSelectInput(app->dpy, app->xkbVirtWindow, ButtonPressMask);
// Force first layuot group on startup
XkbLockGroup(app->dpy, XkbUseCoreKbd, 0);
// Xkb event. X event will be labuda.core
XkbEvent labuda;
// And now main loop!
// TOFIX: create correct thread killing
while (TRUE) {
XNextEvent(app->dpy, &labuda.core);
switch (labuda.core.type) {
case ButtonPress:
g_print("DEBUG! Button pressed!\n");
XkbLockGroup(app->dpy, XkbUseCoreKbd, (app->state + 1) % 4);
break;
default: // XkbLockGroup happens : FIXME
g_print("DEBUG! XkbLockGroup\n");
// Only 2-groups currently supported!
if (app->state == 0) {
app->state = 1;
} else {
app->state = 0;
}
switchFlag();
}
}
}
static gboolean on_icon_clicked (GtkWidget *eb,
GdkEventButton *event,
MainIcon *app) {
// We send event to our XKB-virtual-window
XkbEvent ev;
ev.core.type = ButtonPress;
ev.core.xbutton.button = Button1;
XSendEvent(app->dpy, app->xkbVirtWindow, True, ButtonPressMask, &ev);
// Without this call events not sent permamently!
// WTF?
XCheckMaskEvent(app->dpy, ButtonPressMask, &ev);
return TRUE;
}
static gboolean on_focus_out (GtkWidget *window, GdkEventFocus *event, gpointer null) {
gtk_widget_hide (window);
return TRUE;
}
AwnApplet* awn_applet_factory_initp (const gchar * uid, gint orient, gint height ) {
app = g_new0 (MainIcon, 1);
app->applet = AWN_APPLET (awn_applet_simple_new (uid, orient, height));
app->iconHeight = height;
app->state = 0; // we force first group on startup
app->window = awn_applet_dialog_new (app->applet);
gtk_window_set_focus_on_map (GTK_WINDOW (app->window), TRUE);
g_signal_connect (G_OBJECT (app->window), "focus-out-event",
G_CALLBACK (on_focus_out), NULL);
gtk_widget_set_size_request (GTK_WIDGET (app->applet), 60, -1);
g_signal_connect (G_OBJECT (app->applet), "button-press-event",
G_CALLBACK (on_icon_clicked), (gpointer)app);
//g_signal_connect (G_OBJECT (app->applet), "expose-event",
// G_CALLBACK (_expose_event), (gpointer)app);
// TODO
//app->iconFlag0 = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (), "apport", height - 2, 0, NULL);
app->iconFlag0 = gdk_pixbuf_new_from_file_at_scale("/usr/lib/awn/applets/layoutSwitcher/icons/usflag.svg", height - 2, height - 2, FALSE, NULL);
app->iconFlag1 = gdk_pixbuf_new_from_file_at_scale("/usr/lib/awn/applets/layoutSwitcher/icons/ruflag.svg", height - 2, height - 2, FALSE, NULL);
//GtkWidget *image = gtk_image_new_from_pixbuf(app->iconFlag1);
//gtk_container_add (GTK_CONTAINER (app->box), image);
//gtk_container_add (GTK_CONTAINER (app->window), image);
//app->curIcon = app->iconFlag0;
awn_applet_simple_set_temp_icon (AWN_APPLET_SIMPLE (app->applet), app->iconFlag0);
//awn_applet_simple_set_temp_icon (AWN_APPLET_SIMPLE (app->applet), app->curIcon);
//awn_applet_simple_set_icon (AWN_APPLET_SIMPLE (app->applet), app->iconFlag0);
gtk_widget_show_all (GTK_WIDGET (app->applet));
// Run special XKB-loop in external thread
pthread_t threadId;
int threadMakeResult = pthread_create( &threadId, (pthread_attr_t *)NULL, threadXKBloop, (void* )0);
if (threadMakeResult != 0) {
error_dialog("Thread creating failed!!!", NULL);
}
return app->applet;
}