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