So there is an application I would like to patch. It uses GtkWidget as its topmost container. I would like to do what follows, check number of screens, if it is >2 then check the width of the screen the app is executed on (focus is on screen). I could use Xinerama but first I would like to try native Gtk things. What I do is:
num_monitors = gdk_screen_get_n_monitors (screen);
Then I found a function gdk_screen_get_monitor_at_window(screen, ?window?) but it takes screen and GtkWindow as its argument. Unfortunately I have no window, only widget. I tried to get window by gtk_widget_get_parent_window(widget) or gtk_widget_get_window(widget) these always result in giving me GDK_IS_WINDOW (widget) failed. On the other hand gtk_widget_get_has_window(window) returns 1.
How can I determine screen the app was run on ? I need it to set width hints right.
You're probably failing to get the window because the widget isn't realized and/or mapped, yet. You'll get NULL from gtk_widget_get_window() if it isn't.
The return value from gtk_widget_get_has_window() is probably static; a particular class of widget either always has a window, or never has one.
Try forcing the widget to be realized with gtk_widget_realize(), before extracting the window. If that fails, also try to map it.
You might want to investigate this from the other end, i.e. decide which screen you want/expect the widget to use, and look up that screen's info, without starting from the widget itself.
The window must be actually shown before the function returns you the correct screen the window resides on. This makes your window manager apply its placement policy. To ensure the widget is shown you can use gtk_main_iteration(), calling it until there are no more pending events.
Example code:
#include <stdio.h>
#include <gtk/gtk.h>
int main(int argc, char** argv)
{
gtk_init(&argc, &argv);
GtkWidget*const widget=gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_widget_show(widget);
while(gtk_events_pending())
gtk_main_iteration();
GdkWindow*const window=gtk_widget_get_window(widget);
GdkScreen*const screen=gdk_window_get_screen(window);
const int monitor=gdk_screen_get_monitor_at_window(screen,window);
printf("Monitor number: %d\n",monitor);
}
Related
I'm trying to create a GTK-3 Application and in the initialization process I want to check if the GSetting's value is set, otherwise I want to show a "startup" dialog which will be only on the first run visible.
The GObject's has a _init suffix which can be used for the class initialization. In that case the MyGtkApplication will be constructed, which is based on GtkApplication. The GtkApplication has the startup-thing which can be used for the initialization too.
In that example, I still need to implement the _init function for GApplicationClass.
GApplicationClass *gapp_class;
gapp_class = G_APPLICATION_CLASS (class);
gapp_class->startup = app_startup;
// This must be always implemented, because the MyGtkApplication is "GtkApplication"-based class.
void app_init(MyGtkApplication *app) {
// Check and show the modal dialog if key does not exist?
}
// This will overwrite the GApplicatio's "startup".
void app_startup(GApplication *app) {
// Check and show the modal dialog if key does not exist?
}
Currently app_init does not have a body.
What is the difference and which one should I use?
Regards,
TheAifam5.
init is basically the constructor of the GApplication object. Use it for initializing the object's private data and putting it into a consistent state.
startup is invoked when the application starts. In particular, after you have called g_application_run() and the main event loop is started, and the application has checked that it is the only instance running. You don't want to show dialog boxes before then, so startup is the right place to do that.
I'm new to C and am trying to build a web browser using GTK, but I just can't get tabs to work!
I think this is the relevant code:
#include<gtk/gtk.h>
GtkWidget *window;
GtkWidget *vbox;
GtkWidget *hbox;
GtkWidget *scrollable_window;
GtkWidget *new_tab_button;
GtkWidget *tab_label;
GtkWidget *notebook;
void new_tab() {
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrollable_window, tab_label);
}
int main(int argc, char** argv) {
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_widget_set_size_request(GTK_WIDGET(window), 1300, 768);
tab_label = gtk_label_new ("tab");
scrollable_window = gtk_scrolled_window_new(NULL,NULL);
vbox = gtk_vbox_new(false,false);
hbox = gtk_hbox_new(false,false);
hbox_web_view = gtk_hbox_new(true,0);
notebook = gtk_notebook_new ();
gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP);
gtk_widget_show(notebook);
gtk_container_add(GTK_CONTAINER(window), scrollable_window);
gtk_container_add(GTK_CONTAINER(scrollable_window), vbox);
gtk_container_add(GTK_CONTAINER(vbox), hbox);
gtk_container_add(GTK_CONTAINER(vbox), hbox_web_view);
new_tab_button = gtk_button_new_with_label("New tab");
g_signal_connect(new_tab_button, "clicked", G_CALLBACK(new_tab), web);
gtk_widget_show_all(window);
gtk_main();
return 0;
Everything works, but there is no notebook showing when I open the program. There is a 'new tab' button but whenever I click it it closes the program!
I think I just don't quite understand how gtk notebooks work. Could anyone help me out?
Your code indicates that you are just calling functions without reasoning why you should or not call each function.
The gtk_container_add() adds a widget to another widget that can be a container, i.e. that can contain other widgets, e.g. a GtkBox or the GtkWindow itself.
You are creating the notebook correctly, but you don't add it to any container in the widget hierarchy that has window as it's natural root.
Also, you create a scrollable_window only once but in real life — unless your design is optimizing memory and you know what you're doing — you need multiple scrollable_window instances, in fact you need a web view and all the children you're adding in your code to the window container.
Having mulitple instances of scrollable_window means that you should create each instance in your new_tab() callback, which BTW has a wrong signature, I don't know which the right signature is but it's certainly not that.
Usually GTK gives you
The object that generated the signal as the first parameter of the callback.
A pointer to your own data, that you can use to avoid global variables and make your code more robust and reusable.
There are some callbacks that have extra parameters, you just need to see the signal's documentation to determine which is the correct signature.
Some callbacks (if not all, I don't remember) return a gboolean to indicate whether or not your callback handled the event.
Ideally then,
Create the notebook.
Add the notebook directly to the window container, it should be your root widget.
Create a "browser" in your new_tab() callback, and add it to your notebook. Use the first parameter which is mostly sure of type GtkWidget and is a pointer to your notebook thus eliminating the need for it to be global, don't use global variables, ever.
Use the gpointer data — probably the last parameter to your callback — to store any context data that you need to share with your main() function.
The ideal way to achieve independency, and completely avoid global variables is to create a structure to store your application state, although modern Gtk+ has mechanisms for this, it's still a good idea to store your data somewhere and pass it around to callbacks via the last parameter to g_signal_connect() and receive it as the last parameter to your callbacks.
I have a GUI application which is written in C/gtk+(v 2.x). If I clicked on a menu item of the main window, following function will get called and will show a dialog.
dialog_ui * create_dialog ()
{
dlg = malloc (sizeof(dialog_ui));
dlg->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
...
gtk_widget_show_all (dlg->window);
return dlg;
}
This is the dialog_ui structue
typedef struct _dialog_ui
{
GtkWidget * window;
...
} dialog_ui;
This is the dlg variable in the header file.
dialog_ui * dlg;
My problem is, i'm calling the malloc in the create_dialog function. But I can't figure out from where can I call free, because GUI is event driven. I thought about destroy-event, but I want to know the correct way to do this. Any ideas.. ?
Often times you have a modal dialog which you call using gtk_dialog_run() rather than gtk_widget_show(). The gtk_dialog_run() function will not return until the user closes the dialog, returning a response which you can use to determine if they clicked Yes, Ok, Cancel, Close, etc. You an see an example of that in the GtkDialog API documentation.
Since you're just showing your own GtkWindow, your main application code could connect to the "destroy" signal of the GtkWindow and free the struct that references the widget there.
As a side note, rather than using malloc, you may want to take a look at some of the Memory Allocation functions provided by GLib.
When you don't need the dialog anymore, and you're not going to access it anymore (for example when it's closed) you can free the allocated memory. Doing it in the destroy event is a good place.
I have seen RocketDock redirect the minimize animation in Vista so windows minimize to the dock, and am just curious how this was done. Is the actual minimize animation redirected to the dock, or is something like a hook to stop Windows from minimizing the window and RocketDock has a custom animation when the window is minimized?
I am working on an open source multi-monitor taskbar project called "OpenMMT." I've recently discovered (through many headaches) how to accomplish this.
The following explanation assumes that you know how to go about using RegisterShellHookWindow.
On the window procedure that will receive the shell hooks, look for HSHELL_GETMINRECT.
Now, from here on out is where I had problems. According to MSDN, the lparam member passed contains a pointer to a "SHELLHOOK" object. Which is true, however, I could not get it to work for the simple fact that the "rc" member of that structure, is a RECT that differs from the actual RECT structure in the Windows header files. The RECT in the header files uses LONG for its members, were as on here, we want SHORT.
Anyways, here's a snippet on how I accomplished this.
Structures to define:
typedef struct {
SHORT left;
SHORT top;
SHORT right;
SHORT bottom;
} REALRECT, *LPREALRECT;
typedef struct {
HWND hWnd;
REALRECT rc;
} DOCUMENT_ME_RIGHT_MICROSOFT, *LPDOCUMENT_ME_RIGHT_MICROSOFT;
Then on the Window Procedure:
case HSHELL_GETMINRECT:
{
LPDOCUMENT_ME_RIGHT_MICROSOFT lpShellHook = (LPDOCUMENT_ME_RIGHT_MICROSOFT)lParam;
// lpShellHook now contains all the info. If you want to change the location
// of the animation, simply change the lpShellHook->rc members to point
// to the right coordinates and then return TRUE;
return TRUE;
}
When minimizing programs from my application I encountered some instances where the animation would default back to the original one. I resolved this by minimizing them like so:
void MinimizeApp(HWND hWnd) {
SetForegroundWindow(hWnd);
ShowWindowAsync(hWnd, SW_MINIMIZE);
}
If you want more info regarding my project or you just want to peek at the source, feel free to do so at https://github.com/Fafson/OpenMMT
The ptMinPosition member of the WINDOWPLACEMENT structure specifies the coordinates of the window when it is minimized, so SetWindowPlacement function can be used to that effect. But some testing shows the window should not have a task bar button for that to work (i.e. no WS_EX_APPWINDOW).
I don't know how RocketDock works, but I guess this could be achieved by installing a global WH_CBT hook, and acting upon (setting the ex_style and then setting minimized coordinates) HCBT_MINMAX notification.
You can use the AnimateWindow API function, and pass it e.g. AW_HOR_POSITIVE | AW_VER_POSITIVE to get a diagonal animation.
I'd start with a global hook catching WM_SYSCOMMAND/SC_MINIMIZE, and use AnimateWindow to target the top right corner.
If this doesn't provide the desired effect, the next step would be to use WM_PRINT/WM_PRINTCLIENT to get a copy of the window into a bitmap (I believe this is what AnimateWindow does internally), then hiding the window and doing my own animation.
I'm using pygtk, and would like to handle control+c sometimes to do a special copy action, but other times to let gtk handle it. For example, I'd like to put an object on my clipboard if it is available, or just let control+c be used in the normal fashion in a text entry.
Currently I have an ActionGroup associated with "c" but that always eats the keystroke, even if I return False. If I remove the ActionGroup, it always works in the text areas. If I add the ActionGroup, it always handles it, and copy doesn't work in the text areas.
What is the proper manner to have control+c appear in the menu, handle the keystroke sometimes, but other times, let it fall to a text widget?
I don't know if this is the "proper" way, but here is how I do it. I pass the application window as the user data parameter to the action callback. Then I find out which widget is focused in the window, and I pass the copy command on to that widget if that makes sense to do (i.e. the focused widget is a text entry like you say). If that doesn't make sense, then I copy from the window's 'default' text view.
void
action_copy(GtkAction *action, gpointer user_data)
{
GtkWidget *widget = gtk_window_get_focus(GTK_WINDOW(user_data));
/* What actually happens depends on the type of widget that is focused */
if(WEBKIT_IS_WEB_VIEW(widget))
webkit_web_view_copy_clipboard(WEBKIT_WEB_VIEW(widget));
else if((GTK_IS_LABEL(widget) && gtk_label_get_selectable(GTK_LABEL(widget)))
|| GTK_IS_ENTRY(widget) || GTK_IS_TEXT_VIEW(widget))
g_signal_emit_by_name(widget, "copy-clipboard", NULL);
else
g_signal_emit_by_name(/* ...default text view... */, "copy-clipboard", NULL);
}
(Obtaining the default text view is actually done by calling a get_default_view() method on my application class, which is a subclass of GtkWindow; but I didn't want to complicate matters here.)