1 #include "PersistentTransientWindow.h"
2
3 #include "gtkutil/pointer.h" // for gpointer_to_int
4 #include <iostream>
5
6 namespace gtkutil {
7
PersistentTransientWindow(const std::string & title,GtkWindow * parent,bool hideOnDelete)8 PersistentTransientWindow::PersistentTransientWindow(const std::string& title, GtkWindow* parent,
9 bool hideOnDelete) :
10 TransientWindow(title, parent, hideOnDelete), _parent(parent) {
11 // Connect up a resize handler to the parent window, so that this window
12 // will be hidden and restored along with the parent
13 _parentResizeHandler = g_signal_connect(
14 G_OBJECT(parent),
15 "window-state-event",
16 G_CALLBACK(_onParentResize),
17 this
18 );
19 }
20
~PersistentTransientWindow()21 PersistentTransientWindow::~PersistentTransientWindow() {
22 // greebo: Call the destroy method of the subclass, before
23 // this class gets destructed, otherwise the virtual overridden
24 // methods won't get called anymore.
25 if (GTK_IS_WIDGET(getWindow())) {
26 destroy();
27 }
28 }
29
30 // Activate parent if necessary
activateParent()31 void PersistentTransientWindow::activateParent() {
32 // Only activate if this window is active already
33 if (gtk_window_is_active(GTK_WINDOW(getWindow()))) {
34 gtk_window_present(_parent);
35 }
36 }
37
38 // Post-hide event from TransientWindow
_postHide()39 void PersistentTransientWindow::_postHide() {
40 activateParent();
41 }
42
43 // Virtual pre-destroy callback, called by TransientWindow before the window
44 // itself has been destroyed
_preDestroy()45 void PersistentTransientWindow::_preDestroy() {
46 // If this window is active, make the parent active instead
47 activateParent();
48
49 // Disconnect the resize handler callback from the parent widget
50 g_signal_handler_disconnect(G_OBJECT(_parent), _parentResizeHandler);
51 }
52
_onParentResize(GtkWidget * widget,GdkEventWindowState * event,PersistentTransientWindow * self)53 gboolean PersistentTransientWindow::_onParentResize(GtkWidget* widget, GdkEventWindowState* event,
54 PersistentTransientWindow* self) {
55 // Check, if the event is of interest
56 if ((event->changed_mask & (GDK_WINDOW_STATE_ICONIFIED | GDK_WINDOW_STATE_WITHDRAWN)) != 0) {
57 // Now let's see what the new state of the main window is
58 if ((event->new_window_state & (GDK_WINDOW_STATE_ICONIFIED | GDK_WINDOW_STATE_WITHDRAWN))
59 != 0) {
60 // The parent got minimised, minimise the child as well
61 minimise(self->getWindow());
62 } else {
63 // Restore the child as the parent is now visible again
64 restore(self->getWindow());
65 }
66 }
67
68 return false;
69 }
70
restore(GtkWidget * window)71 void PersistentTransientWindow::restore(GtkWidget* window) {
72 if (GTK_IS_WIDGET(window)) {
73 if (gpointer_to_int(g_object_get_data(G_OBJECT(window), "was_mapped")) != 0) {
74 gint x = gpointer_to_int(g_object_get_data(G_OBJECT(window), "old_x_position"));
75 gint y = gpointer_to_int(g_object_get_data(G_OBJECT(window), "old_y_position"));
76
77 // Be sure to un-flag the window as "mapped", otherwise it will be restored again
78 g_object_set_data(G_OBJECT(window), "was_mapped", gint_to_pointer(0));
79
80 gtk_window_move(GTK_WINDOW(window), x, y);
81
82 // Set the window to visible, as it was visible before minimising the parent
83 gtk_widget_show(window);
84 // Workaround for some linux window managers resetting window positions after show()
85 gtk_window_move(GTK_WINDOW(window), x, y);
86 }
87 }
88 }
89
minimise(GtkWidget * window)90 void PersistentTransientWindow::minimise(GtkWidget* window) {
91 if (GTK_IS_WINDOW(window)) {
92 if (GTK_WIDGET_VISIBLE(window)) {
93 // Set the "mapped" flag to mark this window as "to be restored again"
94 g_object_set_data(G_OBJECT(window), "was_mapped", gint_to_pointer(1));
95
96 // Store the position into the child window
97 gint x, y;
98 gtk_window_get_position(GTK_WINDOW(window), &x, &y);
99 g_object_set_data(G_OBJECT(window), "old_x_position", gint_to_pointer(x));
100 g_object_set_data(G_OBJECT(window), "old_y_position", gint_to_pointer(y));
101
102 gtk_widget_hide(window);
103 }
104 }
105 }
106
107 } // namespace gtkutil
108