I'm trying to get the current keyboard modifiers state through gnome GDK or GTK library in aim to implement an accessibility gnome shell extension that shows that state.
I know how to get thier state using xlib, but there is not full binding for gnome gjs.
The code below get only the initial state. It does not update state.
/*
* compiling: gcc `pkg-config --cflags gdk-3.0` -o gdk_mod gdk_mod.c `pkg-config --libs gdk-3.0`
*/
#include <gdk/gdk.h>
int main (int argc, char **argv) {
gdk_init(&argc, &argv);
GdkDisplay * disp;
disp = gdk_display_open(NULL);
if (disp!=NULL) g_printf("display connected!\n");
GdkKeymap * kmap;
kmap = gdk_keymap_get_for_display(disp);
guint state;
state = gdk_keymap_get_modifier_state(kmap);
g_printf("mod state: %x\n", state);
while (1) {
g_usleep(1000000);
//kmap = gdk_keymap_get_for_display(disp);
state = gdk_keymap_get_modifier_state(kmap);
g_printf("mod state: %x\n", state);
}
}
Here an example output with CAPS lock active then inactive but no change:
$ ./gdk_mod
display found!
mod state: 2
mod state: 2
mod state: 2
mod state: 2
mod state: 2
^C
Currently using Kubuntu 15.04.
What's wrong with my code?
You are going to need to run the GTK+ event loop for this to work. The event loop is part of GLib's main loop. When you call gtk_main(), this main loop is run. I don't know if it polls for events or has events pushed to it, but it won't ask for the keyboard state on the fly like you were trying to do.
The easiest way to set up GDK is to do it via GTK+ by using gtk_init() and gtk_main(). You can use GDK on its own, but I don't know how. You seemed to have figured it out, which works.
And instead of calling g_usleep(), which just blocks your program, you can hook a periodic timeout into the main loop. This is done with g_timeout_add(). The function that you pass to g_timeout_add() returns a Boolean value that decides whether the timer should be stopped or not, so you don't have to worry about rescheduling your function, as GLib will do that for you.
Indeed, I need an event loop as andlabs said in his comment. His suggestion to use GTK gtk_init() & gtk_main() works perfectly.
/*
* compiling: gcc `pkg-config --cflags gtk+-3.0` -o gtk_xkbmod3 gtk_xkbmod3.c `pkg-config --libs gtk+-3.0`
*/
#include <gtk/gtk.h>
static void update(GdkKeymap * kmap) {
guint state;
state = gdk_keymap_get_modifier_state(kmap);
g_printf("%i\n", state);
}
int main (int argc, char **argv) {
gtk_init(&argc, &argv);
GdkKeymap * kmap;
kmap = gdk_keymap_get_default();
g_timeout_add_seconds(1, (GSourceFunc) update, kmap);
gtk_main();
}
I could also use GDK with GLib GMainLoop.
/*
* compiling: gcc `pkg-config --cflags gdk-3.0` -o gdk_xkbmod4 gdk_xkbmod4.c `pkg-config --libs gdk-3.0`
*/
#include <gdk/gdk.h>
GMainLoop *mainloop;
static void update(GdkKeymap * kmap) {
guint state;
state = gdk_keymap_get_modifier_state(kmap);
g_printf("%i\n", state);
}
int main (int argc, char **argv) {
gdk_init(&argc, &argv);
GdkKeymap * kmap;
kmap = gdk_keymap_get_default();
g_timeout_add_seconds(1, (GSourceFunc) update, kmap);
mainloop = g_main_loop_new(g_main_context_default(), FALSE);
g_main_loop_run(mainloop);
}
References:
Xfce Foundation Classes: The Main Event Loop
GTK+ Forums: GDK + GLib main loop
Related
I made a small sample code in gtk4 + vte to run a fake terminal with a button in the bottom to run a simple command when the button is clicked.
main.c
#include <gtk/gtk.h>
#include <vte/vte.h>
#define WINDOW_HEIGHT 400
#define WINDOW_WIDTH 600
GtkApplication *app;
GtkWidget *window, *terminal, *grid, *scrollview1,*button;
int status;
void run_button(void){
char **argv_test[2] = {
"echo\0",
"Hello!!\0"
};
// can't run this command in fake terminal!
vte_terminal_spawn_async(VTE_TERMINAL(terminal),VTE_PTY_NO_HELPER,NULL,argv_test,NULL,G_SPAWN_SEARCH_PATH,NULL,NULL,NULL,2000,NULL,NULL,NULL);
}
void window_renderer(GtkApplication *app, gpointer user_data) {
window = gtk_application_window_new(app);
gtk_window_set_title(GTK_WINDOW(window),"My terminal");
gtk_window_set_default_size (GTK_WINDOW(window), WINDOW_WIDTH, WINDOW_HEIGHT);
grid = gtk_grid_new();
gtk_window_set_child(GTK_WINDOW(window), grid);
gtk_widget_set_vexpand(grid,TRUE);
gtk_widget_set_hexpand(grid,TRUE);
scrollview1 = gtk_scrolled_window_new();
gtk_grid_attach(GTK_GRID(grid), scrollview1, 0, 0, 1, 1);
gtk_widget_set_size_request(GTK_WIDGET(scrollview1),WINDOW_WIDTH,WINDOW_HEIGHT);
button = gtk_button_new_with_label("Run!");
gtk_grid_attach(GTK_GRID(grid), button, 0, 1, 1, 1);
g_signal_connect(button,"clicked", G_CALLBACK(run_button), NULL);
terminal = vte_terminal_new();
gtk_window_set_child(GTK_WINDOW(scrollview1), terminal);
gtk_widget_show(window);
}
int main(int argc, char **argv)
{
app = gtk_application_new(NULL, G_APPLICATION_FLAGS_NONE);
g_signal_connect(app,"activate", G_CALLBACK(window_renderer), NULL);
status = g_application_run(G_APPLICATION(app), argc, argv);
g_object_unref(app);
return status;
}
Makefile
CFLAGS += -Wall
CFLAGS += `pkg-config --cflags gtk4 vte-2.91-gtk4`
LIBS += `pkg-config --libs gtk4 vte-2.91-gtk4`
.PHONY: all clean
all: main
main:main.c
gcc $(CFLAGS) main.c -o main $(LIBS)
clean:
rm main
I have compiled VTE (for gtk4) and gtk4 developer package, building a gtk4 app is not an issue!
When running the built binary, the program crashes when I click the button with a segmentation fault, probably because of a pointer not properly initialized (according to tutorials point).
Can someone help me to find out what I have missed?
I tested out your code and I believe I found the main issue with your terminal command along with some warnings that were displayed when I tested. First off, from reviewing other sample code using the "vte_terminal_spawn_async" function, the character string set included an ending array element of "NULL". So instead of the following code snippet.
char **argv_test[2] = {
"echo\0",
"Hello!!\0"
};
You would need to add in a third array element as in the following revised code snippet.
char *argv_test[3] = {
"echo\0", "Hello!!\0", NULL
};
If you notice one other minor revision to the above code snippet, I revised the definition of the character array from "char ** argv_test[3]" to "char *argv_test[3]". The compiler was listing a warning about incompatible pointer references. Also, when I was testing out this code I was receiving a warning and not able to view the terminal when the "Run" button was clicked.
Gtk-CRITICAL **: 14:49:46.383: gtk_window_set_child: assertion 'GTK_IS_WINDOW (window)' failed
From some previous troubleshooting with another user, we had determined that the child setup for the scrolled window needed to utilize the scrolled window child reference function along with the scrolled window macro. So I revised the scrolled window child assignment to be as follows.
gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scrollview1), terminal);
Making those small revisions resulted in displaying the terminal with your "echo Hello" command (I clicked the button twice in my testing).
I believe that if you try out those minor revisions to your code, you will be able to view your terminal and progress with your coding.
Regards.
I am trying to set the title of a toplevel Motif 2.1 window.
From O'Reilly Volume Six A, I have seen that in Motif 2.1 XtVaOpenApplication is recommended to create a toplevel Widget.
In this appendix it can be seen how options and XtNumber(options) are used to act on resources via argument list.
I have tried to use it to generate an optional flag -title WINDOW_TITLE while invoking the program, without sucess.
This is what I have tried:
#include <stdlib.h>
#include <stdio.h>
#include <Xm/Xm.h>
#include <Xm/PushB.h>
static XrmOptionDescRec options[] = {
{ "-title", "XmNtitle", XrmoptionIsArg, NULL },
};
int main(int argc, char *argv[]) {
Widget toplevel; /* Top Level Button */
XtAppContext app; /* Application Context */
char *window_title = NULL; /* Top Level Window Title */
/* INITIALIZE TOP LEVEL WINDOW */
XtSetLanguageProc(NULL, NULL, NULL);
toplevel = XtVaOpenApplication( &app, argv[0], options, XtNumber(options), &argc, argv, NULL, sessionShellWidgetClass, NULL);
/* REALIZE TOPLEVEL WINDOW AND LAUNCH APPLICATION LOOP */
XtRealizeWidget(toplevel);
XtAppMainLoop(app);
return 0;
}
The program compiles but it does not react to -title MYTITLE command line argument.
This is the makefile (works on FreeBSD 12):
test: test.o
cc -L/usr/local/lib -O -o test test.o -lXm -lXt -lX11
test.o: test.c
cc -I/usr/local/include -c test.c
How can I change the title of the window based on an optional argument named -title?
The correct xrm option line is
{"-title", ".title", XrmoptionSepArg, NULL}
You don't actually need to specify it because it is in the default Xt option table.
In general you omit XmN when specifying xrm resource names.
In my Motif programs, I use Xlib directly, since Motif does not seem to handle correctly the UTF8 setting of window titles using XmNtitle property. Most modern window managers expect UTF8 string passed as _NET_MW_NAME.
void setWindowTitleUTF8(Widget w, char *title)
{
static Atom atoms[3];
static bool first = TRUE;
if (first)
{
static char *atom_names[] = {"_NET_WM_NAME", "_NET_WM_ICON", "UTF8_STRING"};
first = FALSE;
XInternAtoms(XtDisplay(w), atom_names, 3, FALSE, atoms);
}
XChangeProperty(XtDisplay(w), XtWindow(w), atoms[_NET_WM_NAME], atoms[UTF8_STRING], 8,
PropModeReplace, (unsigned char *) title, strlen(title));
}
Make sure you call it on XtParent() of your widget, so it is applied to top level widget shell.
Please investigate further yourself (I'm no X/Motif expert), but sth seems to be off with the argument parsing.
Replacing options with NULL ant its size with 0 in call XtVaOpenApplication call seems to do the trick:
toplevel = XtVaOpenApplication( &app, argv[0], NULL, 0, &argc, argv, NULL, sessionShellWidgetClass, NULL);
I'm trying to create a simple gui using glade and gtk in C. In the GUI I want to add a widget that plots data (a line plot and a histogram are all I want) (constantly updating) and I dont know what to use. I've seen that gnuplot is popular, but I have no idea how to use it in an application. I would like some suggestions and some instructions because I cannot find it.
here is some sample code that is what I am using as a base, just to give you an idea
update:
I built gnuplot on my pc and now when I run the code it doesnt open a new window and seems to plot inside my window. the only problem is that the widget in my gtkbox container doesnt resize so it looks like a tiny white bar. Im assuming that it is working because i removed
gui.graph = gnuplot_init() ;
gnuplot_setstyle(gui.graph, "lines") ;
gnuplot_cmd(gui.graph, "set terminal x11 window \"%x\"", (int)gtk_socket_get_id (gui.socket));
gnuplot_plot_slope(gui.graph, 1.0, 0.0, "unity slope") ;
and ran the commands on a seperate terminal and the white bar i mentioned pops up.
#include <gtk/gtk.h>
#include <gtk/gtkx.h>
#include "variables.h"
#include "gnuplot_i.h"
struct test tv;
struct GUI gui;
// Functions
void GUISetup();
int main(int argc, char *argv[])
{
gtk_init(&argc, &argv);
gui.builder = gtk_builder_new_from_file("glade/window_main.glade");
gui.window = GTK_WIDGET(gtk_builder_get_object(gui.builder, "window_main"));
gtk_builder_connect_signals(gui.builder, NULL);
GUISetup();
g_object_unref(gui.builder);
// start fullbuilderscreen
gtk_window_fullscreen(GTK_WINDOW(gui.window));
gtk_widget_show(gui.window);
gtk_main();
return 0;
}
void GUISetup(){
gui.socket = gtk_socket_new ();
gtk_container_add (GTK_CONTAINER (gui.MainContainer), gui.socket);
//gtk_widget_show (gui.socket);
//gtk_widget_realize (gui.socket);
gui.graph = gnuplot_init() ;
gnuplot_setstyle(gui.graph, "lines") ;
gnuplot_cmd(gui.graph, "set terminal x11 window \"%x\"", (int)gtk_socket_get_id (gui.socket));
gnuplot_plot_slope(gui.graph, 1.0, 0.0, "unity slope") ;
}
when I make I get this:
gcc -c -g -O0 -Wall -pthread -pipe src/main.c `pkg-config --cflags --libs gtk+-3.0` -o main.o
src/main.c: In function ‘GUISetup’:
src/main.c:66:86: warning: passing argument 1 of ‘gtk_socket_get_id’ from incompatible pointer type [-Wincompatible-pointer-types]
ui.graph, "set terminal x11 window \"%x\"", (int)gtk_socket_get_id (gui.socket));
^~~
In file included from /usr/include/gtk-3.0/gtk/gtkx.h:29:0,
from src/main.c:25:
/usr/include/gtk-3.0/gtk/gtksocket.h:81:12: note: expected ‘GtkSocket * {aka struct _GtkSocket *}’ but argument is of type ‘GtkWidget * {aka struct _GtkWidget *}’
Window gtk_socket_get_id (GtkSocket *socket_);
^~~~~~~~~~~~~~~~~
gcc -o interface main.o gnuplot_i.o -pthread `pkg-config --cflags --libs gtk+-3.0` -export-dynamic
i tested the code manually and got the same results as found here, so I am going to try building gnuplot and altering the config files. Is there any alternative to the solution found in that post?
For gnuplot:
http://ndevilla.free.fr/gnuplot/gnuplot_i/index.html
Or you can use Gtk::Socket, start by create an Gtk::Socket
and add it to your widget. Then pass the socket ID (as hex) to gnuplot 'set
terminal x11 window "ID"'. And that's it!
Matplot can be better:
https://github.com/lava/matplotlib-cpp
I was trying to play around a bit with SDL on macOS (High Sierra 10.13.2) and I stumbled on what seems to be a rather incomprehensible mistake involving SDL windows not responding to keystrokes. I tried to construct two minimally different examples demarcating when this problem occurs: in fact, the examples do differ so minimally that it seems bizarre that their behaviour differs at all.
I have version 1.2.15 of the SDL libraries installed, and they were installed using the 'brew install sdl' command.
The first example (the one that does work correctly) is as follows:
/* sdl1.c */
#include "SDL/SDL.h"
SDL_Surface *screen;
SDL_Event event;
void initsdl (void) {
SDL_Init (SDL_INIT_EVERYTHING);
screen = SDL_SetVideoMode (500, 250, 32, SDL_SWSURFACE);
SDL_EnableKeyRepeat (SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
while (1)
if (SDL_PollEvent(&event))
if (event.type == SDL_KEYDOWN)
if (event.key.keysym.sym == SDLK_ESCAPE)
break;
SDL_Quit ();
}
int main (int argc, char **argv) {
initsdl ();
return 0;
}
The other example is almost identical, but is spread over two files.
/* sdl2a.c */
#include "SDL/SDL.h"
SDL_Surface *screen;
SDL_Event event;
void initsdl (void) {
SDL_Init (SDL_INIT_EVERYTHING);
screen = SDL_SetVideoMode (500, 250, 32, SDL_SWSURFACE);
SDL_EnableKeyRepeat (SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
while (1)
if (SDL_PollEvent(&event))
if (event.type == SDL_KEYDOWN)
if (event.key.keysym.sym == SDLK_ESCAPE)
break;
SDL_Quit ();
}
With the second file being:
/* sdl2b.c */
void initsdl(void);
int main (int argc, char **argv) {
initsdl ();
return (0);
}
As you can see, these programs are close to identical, with the only real difference being the fact that one of them is spread out over two files.
Now, I compile these files with the commands
cc -Wall -o sdl1 sdl1.c `sdl-config --libs` # (1)
and
cc -Wall -o sdl2 sdl2a.c sdl2b.c `sdl-config --libs` # (2)
I get two differences in the resulting behaviour.
First of all, the first example does not give any warnings whatsoever, whereas the second example gives the following warning:
ld: warning: object file (/usr/local/lib/libSDLmain.a(SDLMain.o)) was built for newer OSX version (10.13) than being linked (10.12)
The second difference is more problematic, however. Whereas the first example (the one who does give a compiler warning) behaves as it should, with a window appearing on screen, which correctly responds to the pressing of the ESC key before quitting, the second example simply does not respond to keystrokes at all, even after clicking on the window to make it active. This result is obtained by executing the binary resulting from the compilation directly from the terminal.
i was doing a small project where i had a a fullscreen GUI (Glade, GTK and C) and needed to give the user a way to close the screen (obviously the window manager was not available due to the window being fullscreen).
problem rices when i attempt to compile this piece of code
//close sidebar1
void on_window_sidebar1_back_clicked()
{
gtk_window_close (GtkWindow *window);
}
i receive the following error
/usr/bin/arm-linux-gnueabihf-gcc -c -g -O0 -Wall -pthread -pipe src/main.c `pkg-config --cflags --libs gtk+-3.0` -o main.o
src/main.c: In function 'on_window_sidebar1_back_clicked':
src/main.c:61:2: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'gtk_window_close'
gtk_window_close (GtkWindow *window);
^
src/main.c:61:20: error: expected expression before 'GtkWindow'
gtk_window_close (GtkWindow *window);
^
makefile:30: recipe for target 'main.o' failed
make: *** [main.o] Error 1
I tried to follow the documentation here, but seem to have failed badly
Does anyone have any ideas?
PS.
here is the full main.c if someone is intrested. Its my first attempt at C with gtk, so dont be too harsh, Thank you (=
#include <gtk/gtk.h>
GtkWidget *g_lbl_test;
GtkWidget *g_lbl_count;
int main(int argc, char *argv[])
{
GtkBuilder *builder;
GtkWidget *window;
gtk_init(&argc, &argv);
builder = gtk_builder_new();
gtk_builder_add_from_file (builder, "glade/window_main.glade", NULL);
window = GTK_WIDGET(gtk_builder_get_object(builder, "window_main"));
gtk_builder_connect_signals(builder, NULL);
//pointers for the labels (...used in button press)
g_lbl_test = GTK_WIDGET(gtk_builder_get_object(builder, "lbl_test"));
g_lbl_count = GTK_WIDGET(gtk_builder_get_object(builder, "lbl_count"));
g_object_unref(builder);
gtk_widget_show(window);
//gtk_window_fullscreen (GtkWindow *window); //dont know how to use this, same with gtk_window_close
gtk_main();
return 0;
}
//button press (just a test to make sure the window didnt freeze)
void on_btn_count_clicked()
{
static unsigned int count= 0;
char str_count[30] = {0};
gtk_label_set_text(GTK_LABEL(g_lbl_test), "Test success!");
count++;
sprintf(str_count, "%d", count);
gtk_label_set_text(GTK_LABEL(g_lbl_count), str_count);
}
//sidebar1
void on_sidebar_1_clicked()
{
GtkBuilder *builder;
GtkWidget *window;
builder = gtk_builder_new();
gtk_builder_add_from_file (builder, "glade/window_main.glade", NULL);
window = GTK_WIDGET(gtk_builder_get_object(builder, "window_sidebar1"));
gtk_widget_show(window);
}
//close sidebar1
void on_window_sidebar1_back_clicked()
{
gtk_window_close (GtkWindow *window);
}
// called on closing window
void on_window_main_destroy()
{
gtk_main_quit();
}
You probably should call
gtk_close_window(window);
But that window should come from somewhere.
(you may use a Gtk closure with a connection, or a callback with a client data, etc. or store somehow that window in a global variable, etc...)
Read more about C programming, then read a bit about callbacks and closures, then read more about GTK, and the signal mechanism of Gobject.
(your code shows a lot of confusion; I suggest to read the Getting started with GTK chapter after having read a good C programming book; BTW, I suggest to first write something which is not fullscreen, and only later improve it)
Don't forget to enable all warnings and debug info when compiling, that is compile with gcc -Wall -Wextra -g (and other arguments, perhaps using $(pkg-config --cflags gtk+-3.0) and also $(pkg-config --libs gtk+-3.0) for linking).
Attention! This does not follow any industrial standards and there are multiple flaws in this. I don't make any money or fame out of this so my only requirement is that it works. Take this into consideration when reading this!
I made edits to my code with what I learned and this seems to work:
void on_sidebar_1_clicked(int argc, char *argv[])
{
GtkBuilder *builder;
gtk_init(&argc, &argv);
builder = gtk_builder_new();
gtk_builder_add_from_file (builder, "glade/window_sidebar1.glade", NULL); //a whole own file for the second window
secondWindow = GTK_WIDGET(gtk_builder_get_object(builder, "window_sidebar1")); //secondWindow is defined at the start of main.c like this: "GtkWidget *secondWindow = NULL;" so that both callbacks can use it.
gtk_builder_connect_signals(builder, NULL);
gtk_widget_show(secondWindow);
gtk_main();
}
void on_sidebar1_back_clicked()
{
gtk_widget_destroy(GTK_WIDGET(secondWindow)); //here we call the widget to be closed instead of the window. Seems to work a lot better than the gtk_window_close, dunno why.
}
This code was written fast (and furious) so it's a little crude. I made some changes to my glade files as well, if someone needs a reference to those, please ask. As far as I care, this was the answer for my question. Also, I would recommend learning C and GTK (like Basile Starynkevitch said) before you start doing this kind of stuff, I didn't have the time nor motivation to do so.