I'm trying to save the gtk window position(absolute) to restore it wehn I open the applicaiton again
here's my code so far:
gint x,y;
gtk_window_get_position(main_window,&x,&y);
printf("current position is:\nx: %i\ny:%i\n",x,y);
this code runs when the application exits, I always get:
current position is:
x: 0
y:0
What am I doing wrong.
gtk_window_get_position usually does a best guess but you cannot rely on it because
the X Window System does not specify a way to obtain the geometry of
the decorations placed on a window by the window manager.
(from gtk_window_get_position reference)
To see the function in action, try something like below:
#include <gtk/gtk.h>
int main(int argv, char* argc[])
{
GtkWidget *window, *button;
gint x, y;
gtk_init(&argv, &argc);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), "Test Window");
button = gtk_button_new_with_label("Close");
g_signal_connect(G_OBJECT(button), "clicked",
G_CALLBACK(gtk_main_quit), (gpointer)NULL);
gtk_container_set_border_width(GTK_CONTAINER(window), 10);
gtk_container_add(GTK_CONTAINER(window), button);
gtk_window_get_position(GTK_WINDOW(window), &x, &y);
printf("current position is:\nx: %i\ny:%i\n", x, y);
gtk_window_set_position(GTK_WINDOW(window),
GTK_WIN_POS_CENTER_ALWAYS);
gtk_window_get_position(GTK_WINDOW(window), &x, &y);
printf("new position is:\nx: %i\ny:%i\n", x, y);
gtk_widget_show_all(window);
gtk_main();
}
Edit
If you wish the window to appear at a specific location, you could try something like:
gtk_window_move(GTK_WINDOW(window), 420, 180);
However the above function should be placed after
gtk_widget_show_all(window);
because
most window managers ignore requests for initial window positions
(instead using a user-defined placement algorithm) and honor requests
after the window has already been shown.
(from gtk_window_move reference)
I've just implemented this feature using pygobject; it's not C but it could still be useful to have a look at it.
You can find the code here.
I've used GNOME Builder's default template for a python GNOME application, so it should be super-easy to replicate if you set your project with it.
Related
I have a task to restore window frame position on screen on program startup - so to define initial window position.
Consider the following decorated GtkWindow instance on Linux:
The window has two principal boxes: frame box and client box.
And there are two GTK functions that allow to set size and position of the window on screen:
gtk_window_move() - sets window's frame box position on screen and
gtk_window_resize - sets window's client box size.
Question:
Is there any way in GTK to define initial frame placement of the window?
On Windows I can do that by calling MoveWindow() and on MacOS NSWindow setFrame method. But on GTK... Am I asking too much?
Connect to the "realize" signal for the window (important: before calling gtk_widget_show). Then call gtk_window_move from the handler:
#include <gtk/gtk.h>
void on_window_realize(GtkWidget *widget,
gpointer user_data)
{
GtkWindow *window = GTK_WINDOW(user_data);
gtk_window_move(window, 100, 40);
}
int main(int argc, char **argv) {
GtkWidget *window = NULL;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(window,
"realize",
G_CALLBACK(on_window_realize),
(gpointer)window);
g_signal_connect(window, "destroy", gtk_main_quit, NULL);
gtk_widget_show(window);
gtk_main();
return 0;
}
I'm writing a C program using the GTK libraries that reads the position of the cursor and writes it out to another function. I've written code that's able to accurately read the cursor position data, but I can't figure out how to connect a cursor motion event to a function.
Here is the code I have so far:
int main(int argc, char **argv){
GdkWindow *window;
GtkWidget *gtk_window;
GdkDevice *mouse;
gint x = 0;
gint y = 0;
gdk_init(&argc, &argv);
gtk_init(&argc, &argv);
gtk_window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_widget_show(gtk_window);
window = gtk_widget_get_window(GTK_WIDGET(gtk_window));
gdk_window_maximize(window);
gdk_window_set_title(window, "write-mouse");
GdkSeat *seat = gdk_display_get_default_seat (gdk_display_get_default ());
mouse = gdk_seat_get_pointer (seat);
gdk_window_get_device_position (window, mouse, &x, &y, NULL);
//read cursor position at startup to test code
g_print("X = %d\n", x);
g_print("Y = %d\n", y);
//g_signal_connect (mouse, "something?", G_CALLBACK (print_mouse), NULL);
gtk_main();
}
static void print_mouse(GdkDevice *mouse, gpointer data){
gint x = 0;
gint y = 0;
//do I need to pass the window object to "print_mouse" function too?
//can I point to it using some gtk function?
gdk_window_get_device_position (window, mouse, &x, &y, NULL);
g_print("X = %d\n", x);
g_print("Y = %d\n", y);
}
I assume I need to use "g_signal_connect()" to connect the cursor motion event to the "print_mouse" function, but I can't figure out what to put as the arguments to make it work.
What should I put in the "detailed_signal" field of "g_signal_connect()?
Is there a better way to do this entirely?
your something is "motion-notify-event" which gives data as a GdkEventMotion event: https://developer.gnome.org/gtk2/stable/GtkWidget.html#GtkWidget-motion-notify-event
I think you will also need to ensure to gtk_widget_add_events(widget, GDK_POINTER_MOTION_MASK); when constructing the widget. For performance reasons you may want to set this up to only run code at a certain refresh rate so as not too overburden the cpu.
I am developping a small GTK+ program in which I placed a GtkDrawingArea. I use it in order to draw a rather specific kind of data representation graph, and the result is quite satisfying.
The problem is: the "graph" has a lot of data to process, and the draw signal's callback is called quite often. Most importantly, it is called every time the window (GtkWindow/GtkContainer) is resized by a few pixels. In order to avoid slowing down the application too much, I'd like to "suspend" the draw callbacks while the window is being resized. We could imagine that the whole area would be covered with a gray rectangle in the meantime, or something similar...
gboolean draw_callback(GtkWidget* widget, cairo_t* cr, gpointer data){
/* A lot of drawing with Cairo
* This is called WAY too often. */
}
int main(int argc, char* argv[]){
GtkBuilder* builder;
GtkWidget *window;
GtkWidget *draw_area;
gtk_init(&argc, &argv);
builder = gtk_builder_new_from_file("myapp.ui");
window = GTK_WIDGET(gtk_builder_get_object(builder, "main_window"));
draw_area = GTK_WIDGET(gtk_builder_get_object(builder, "draw_area"));
g_signal_connect(draw_area, "draw", G_CALLBACK(draw_callback), NULL);
gtk_widget_show_all(GTK_WIDGET(window));
g_object_unref(builder);
gtk_main();
return 0;
}
Note: the callbacks must still be executed once the window is resized (some coordinates need to be recomputed when that happens). I'm just trying to avoid it while the window is being resized.
My first idea was to connect a callback to the check-resize event, in which a boolean could be set and unset, as the window is grabbed and released (while resizing) :
gboolean resizing = false;
void resize_callback(GtkContainer* container, gpointer data){
/* Set "resizing"...
* Is the window being grabbed? Released? */
}
gboolean draw_callback(GtkWidget* widget, cairo_t* cr, gpointer data){
if(resizing){
/* Draw a gray overlay or something if necessary... */
return true;
}
/* Draw the actual stuff here... */
}
int main(int argc, char* argv[]){
GtkWidget *window;
GtkWidget *draw_area;
// ...
g_signal_connect(window, "check-resize", G_CALLBACK(resize_callback), NULL);
g_signal_connect(draw_area, "draw", G_CALLBACK(draw_callback), NULL);
// ...
}
However this event doesn't really suit me because it is not triggered when the window is being grabbed/released (only when its size actually changes).
Is there a way to be notified when the window is being grabbed and released (for resizing) ? Or is there a better way to suspend/simplify the calls to draw_callback when the window is being resized?
Consider blocking the draw callback while the mouse button is down. Save the callback id:
draw_callback_id = g_signal_connect(draw_area, "draw",
G_CALLBACK(draw_callback), NULL);
When the button-pressed signal is detected, do
g_signal_handler_block(draw_area, draw_callback_id);
And, of course, after the button-release-event:
g_signal_handler_block(draw_area, draw_callback_id);
You could then manually trigger a redraw event. To optimize, you can use the gtk_widget_queue_draw_region() call, which only redraws the specified rectangle.
Another possibility (though I haven't tried this) could be drawing only the window borders while resizing or moving. The Window manager (XFCE) has this option, but I haven't seen how to do it from inside GTK.
I want to maximize my Widget and then make it non-resizable. I can maximize the Widget with:
gtk_window_maximize(GTK_WINDOW(window));
But when I try to make it non-resizable with:
gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
The window lost its maximized state; it returned to its original size.
Why? How can a Widget be maximized and made non-resizable?
Disclaimer: This answer is proposed as a workaround only, and does not actually solve the problem.
After following #ptomato's link, this is the closest thing I got:
int main(int argc, char *argv[]) {
gtk_init(&argc, &argv);
GtkWidget *win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_widget_show(win);
GdkScreen *screen = gtk_window_get_screen(GTK_WINDOW(win));
GdkRectangle rect;
gdk_screen_get_monitor_workarea(screen, 0, &rect);
gtk_window_move(GTK_WINDOW(win), rect.x, rect.y);
gtk_widget_set_size_request(win, rect.width, rect.height);
gtk_window_set_resizable(GTK_WINDOW(win), FALSE);
gtk_main();
return 0;
}
However, this is still not perfect, and differs from a maximised window in the following ways (tested using the default Ubuntu 14.04 theme):
The width and height of the window is very slightly larger (by a few pixels) than the monitor size minus the title bar and the launch bar.
In addition to the system title bar the window also has its own title bar.
You can move the window around, while you shouldn't be able to if it is maximised.
What my code (below) does:
Creates a XLIB window with a background color
Draws a string on the window
Draws a line on the window
Creates a GTK+ window
Makes the GTK+ window realise the XLIB window exsists via a GDK window
Display the output of the XLIB window inside the GTK+ window
It works and creates a window of the correct colour but it doesn't draw the string or the line on the screen. Any ideas of how to make it appear or where im going wrong?
The reason I am not using the GTK+ drawing functions is because this a test program in reality all the drawing needs to come from the xlib window.
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#include <X11/Xlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void destroy(GtkWidget *widget, gpointer data ) {
gtk_main_quit ();
}
int main(int argc, char** argv) {
GtkWidget *xwindow;
//Open the display
Display *display = XOpenDisplay(NULL);
int screen = DefaultScreen(display);
//Create the window
Window w = XCreateSimpleWindow(display, DefaultRootWindow(display), 0, 0,
200, 100, 20, black, 10201020);
XSelectInput(display, w, StructureNotifyMask);
XMapWindow(display, w);
GC gc = XCreateGC(display, w, 0, NULL);
for(;;) {
XEvent e;
XNextEvent(display, &e);
if (e.type == MapNotify)
break;
}
XDrawString(display, w, gc, 10, 10, "HelloWorld!", 12);
XDrawLine(display, w, gc, 10, 60, 180, 20);
XFlush(display);
//SET UP
gtk_init (&argc, &argv);
//xwindow
xwindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect (xwindow, "destroy",
G_CALLBACK (destroy), NULL);
g_signal_connect (xwindow, "destroy",
G_CALLBACK (print), NULL);
gtk_widget_realize(xwindow);
xwindow->window = gdk_window_foreign_new((guint32)w);
//SET UP
gtk_widget_show(xwindow);
gtk_main ();
return 0;
}
I believe this is simply due to a misunderstanding of what "drawing" really means, here.
The Xlib drawing model isn't "state-ful", it won't remember that your particular window has had some text drawn in a particular location, and then a line, and so on. The drawing happens immediately when you request it, and is then considered "done", i.e. forgotten about at the protocol level.
When you wrap the X window in a GTK+ widget, it will likely cause the X window system to attempt to refresh the contents of the X window, but that doesn't do anything, which is why your initial graphics are lost.
In short, you need to be able to respond to requests to redraw the window as needed.