Merge lp:~elementary-apps/granite/saved-state into lp:~elementary-pantheon/granite/granite

Proposed by Raphael Isemann
Status: Rejected
Rejected by: xapantu
Proposed branch: lp:~elementary-apps/granite/saved-state
Merge into: lp:~elementary-pantheon/granite/granite
Diff against target: 250 lines (+229/-1)
2 files modified
lib/CMakeLists.txt (+2/-1)
lib/Services/SavedState.vala (+227/-0)
To merge this branch: bzr merge lp:~elementary-apps/granite/saved-state
Reviewer Review Type Date Requested Status
xapantu (community) Disapprove
Rico Tzschichholz Needs Information
Review via email: mp+232092@code.launchpad.net

Description of the change

The current system of the saved-state logic is currently done by each app on their own, and the result is either half-implemented, wrong-implemented, not-implemented or twice-implemented processes for syncing the window-state to the gsettings-backend.

This branch adds a simple API extension to Granite that allows to sync a specified window to a single specified gsettings-key.

To test this branch i implemented a useage of this API in Terminal: https://code.launchpad.net/~elementary-apps/pantheon-terminal/new-saved-state/

To post a comment you must log in.
Revision history for this message
Rico Tzschichholz (ricotz) wrote :

This is what is suppose to be achieved with the following:

http://valadoc.org/#!api=gio-2.0/GLib.Settings.bind
http://valadoc.org/#!api=gio-2.0/GLib.Settings.bind_with_mapping
http://valadoc.org/#!api=gio-2.0/GLib.Settings.bind_writable

Besides that "SavedState" is not really descriptive enough since only Gtk.Windows are supported

review: Needs Information
Revision history for this message
Raphael Isemann (teemperor) wrote :

SavedState is not a good description. We want that it takes care of saving/restoring the window-geometry over long durations, so we could name it "PersistentWindowManager"? I'm open for suggestions. We probably also want to rename the key from "saved-state" to something like "saved-geometry".

I'm not sure what you mean with "This is what is suppose to be achieved with the following: ..."? That we should have one Variant that we bind to a GSettings-key?

Revision history for this message
David Gomes (davidgomes) wrote :

Wouldn't it be better to have our own Granite.Window, instead of a wrapper class like you made? I mean, if it is doable, of course.

Revision history for this message
Raphael Isemann (teemperor) wrote :

Sounds reasonable and would solve the naming problem.

So it would be just using Granite.Window that has a property for a gsettings-path where it would save its geometry.

Revision history for this message
Akshay Shekher (voldyman) wrote :

hmm, my idea was of storing and restoring windows state from applications that use Granite.Application transparently.

Gtk.Application has signals for window_added and window_removed, we could use those signals to get the dimensions of the windows when they were closed and restore when the same window is opened again.

I haven't thought enough about this so it is open for debate.

Revision history for this message
xapantu (xapantu) wrote :

I also think this must be done more transparently. Maybe a set_main_window call or whatever would be required, but that should be all. Creating a new object and calling several functions for such a simple task is not very good. Besides, as Rico said, it would be better to bind the properties, else that will make a lot of code for nothing.

review: Disapprove

Unmerged revisions

783. By Raphael Isemann

Added support for maximized_fullscreen and fixed the saving of the window-state to the dconf-base (before we used the wrong method with the same name from Gtk.Widget instead of Gdk.Window). Also moved the methods to the upper part of the class and expanded documentation a bit.

782. By Raphael Isemann

Fixed saved-state parsing and fixed setting the window-size

781. By Raphael Isemann

We moved to a single key now as the backend

780. By Raphael Isemann

Added SavedState class

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/CMakeLists.txt'
--- lib/CMakeLists.txt 2014-01-18 21:47:46 +0000
+++ lib/CMakeLists.txt 2014-08-25 14:36:17 +0000
@@ -12,6 +12,7 @@
12 Drawing/Utilities.vala12 Drawing/Utilities.vala
13 GtkPatch/AboutDialog.vala13 GtkPatch/AboutDialog.vala
14 Services/Settings.vala14 Services/Settings.vala
15 Services/SavedState.vala
15 Services/Logger.vala16 Services/Logger.vala
16 Services/Paths.vala17 Services/Paths.vala
17 Services/System.vala18 Services/System.vala
@@ -114,4 +115,4 @@
114if (INTROSPECTION_FOUND)115if (INTROSPECTION_FOUND)
115 include (GObjectIntrospectionMacros)116 include (GObjectIntrospectionMacros)
116 add_target_gir (${PKG_NAME} ${PKG_GIR_NAME} ${PKG_NAME}.h "${VALA_C}" "${DEPS_CFLAGS}" ${API_VERSION} ${GI_PKG_DEPS})117 add_target_gir (${PKG_NAME} ${PKG_GIR_NAME} ${PKG_NAME}.h "${VALA_C}" "${DEPS_CFLAGS}" ${API_VERSION} ${GI_PKG_DEPS})
117endif ()
118\ No newline at end of file118\ No newline at end of file
119endif ()
119120
=== added file 'lib/Services/SavedState.vala'
--- lib/Services/SavedState.vala 1970-01-01 00:00:00 +0000
+++ lib/Services/SavedState.vala 2014-08-25 14:36:17 +0000
@@ -0,0 +1,227 @@
1/***
2 Copyright (C) 2014 Raphael Isemann <raphael@elementaryos.org>
3
4 This program or library is free software; you can redistribute it
5 and/or modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 3 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General
15 Public License along with this library; if not, write to the
16 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301 USA.
18***/
19
20namespace Granite.Services {
21
22 /**
23 + The SavedState class provides a synchronizing mechanism between
24 * the properties of a Gtk.Window and a gsettings-schema for saving
25 * those properties.
26 *
27 * The only action in your code is creating a SavedState-object, the rest is
28 * handled by this class:
29 * {{{
30 * new SavedState (my_app_window, "org.example.myapp");
31 * }}}
32 *
33 * Note that you should use this code between the show_all () and the end of
34 * your UI-setup phase to prevent unwanted side-effects.
35 *
36 * You also need a proper saved-state key in your schema with the name "saved-state"
37 * and with the type '(iiiiu)'
38 * where the types represent in the order of listing:
39 * x-coordinate of the window (the value -1 means centered window),
40 * y-coordinate of the window (the value -1 means centered window),
41 * width of the window,
42 * height of the window,
43 * state of the window (0 = Normal, 1 = Maximized, 2 = Fullscreen).
44 *
45 * This is an example-of such an gsettings-key in your myapp.gschema.xml:
46 *
47 * {{{
48 * ...
49 * <key name="saved-state" type="(iiiiu)">
50 * <default>(-1,-1,700,500,0)</default>
51 * <summary>The saved state of the window.</summary>
52 * <description>The saved width of the window. The values represent in the respective order:
53 * x-coordinate of the window (the value -1 means centered window),y-coordinate of the window (the value -1 means centered window),
54 * width of the window, height of the window, state of the window (0 = Normal, 1 = Maximized, 2 = Fullscreen).</description>
55 * </key>
56 * ...
57 * }}}
58 *
59 */
60 public class SavedState {
61
62 SavedStateBackend backend;
63 Gtk.Window window;
64
65 /**
66 * Connects the given window to the saved-state in the given schema.
67 * All window-contents should haven been be added when this constructor
68 * is called.
69
70 * @param key_name The key for the gsettings-field that should contain
71 * the saved-state. Default is "saved-state".
72 */
73 public SavedState (Gtk.Window window, string schema, string key_name = "saved-state") {
74 backend = new SavedStateBackend (schema, key_name);
75 this.window = window;
76 window.delete_event.connect (() => {
77 update_backend ();
78 return false;
79 });
80
81 // we update the window directly at the end of this constructor
82 update_window ();
83 }
84
85 /**
86 * Updates the saved-state backend. You only need to call this method
87 * if you expect that the app could quit without proper shutting down
88 * the UI. This class will otherwise automatically call this function
89 * when the window is deleted.
90 */
91 public void update_backend () {
92 backend.state = get_window_state ();
93
94 int width, height;
95 window.get_size (out width, out height);
96 backend.width = width;
97 backend.height = height;
98
99 int window_x, window_y;
100 window.get_position (out window_x, out window_y);
101 backend.x = window_x;
102 backend.y = window_y;
103
104 backend.write ();
105 }
106
107 /**
108 * Updates the window with the values from the saved-state.
109 * We keep this method private as saved-state is not supposed to react
110 * to during-runtime changes to the gsettings-backend.
111 */
112 private void update_window () {
113
114 window.set_size_request (backend.width, backend.height);
115
116 if (backend.x != -1 && backend.y != -1) {
117 window.move (backend.x, backend.y);
118 }
119
120 if (backend.state == WindowState.MAXIMIZED
121 || backend.state == WindowState.MAXIMIZED_FULLSCREEN) {
122 if (get_window_state () != WindowState.MAXIMIZED) {
123 window.maximize ();
124 }
125 }
126 if (backend.state == WindowState.FULLSCREEN
127 || backend.state == WindowState.MAXIMIZED_FULLSCREEN) {
128 if (get_window_state () != WindowState.FULLSCREEN) {
129 window.fullscreen ();
130 }
131 }
132 if (backend.state == WindowState.NORMAL) {
133 // In case the window is maximized or in fullscreen-mode
134 // we bring it back as a normal window
135 if (get_window_state () == WindowState.FULLSCREEN) {
136 window.unfullscreen ();
137 } else if (get_window_state () == WindowState.MAXIMIZED) {
138 window.unmaximize ();
139 }
140 }
141 }
142
143 private enum WindowState {
144 NORMAL = 0,
145 MAXIMIZED = 1,
146 FULLSCREEN = 2,
147 MAXIMIZED_FULLSCREEN = 3
148 }
149
150 private WindowState get_window_state () {
151 Gdk.Window gdk_window = window.get_window ();
152 if ((gdk_window.get_state () & Gdk.WindowState.MAXIMIZED) != 0) {
153 if ((gdk_window.get_state () & Gdk.WindowState.FULLSCREEN) != 0) {
154 return WindowState.MAXIMIZED_FULLSCREEN;
155 } else {
156 return WindowState.MAXIMIZED;
157 }
158 } else if ((gdk_window.get_state () & Gdk.WindowState.FULLSCREEN) != 0) {
159 return WindowState.FULLSCREEN;
160 } else {
161 return WindowState.NORMAL;
162 }
163 }
164
165 /**
166 * Helper class to pass values to the gsettings-backend.
167 */
168 private class SavedStateBackend : Object{
169
170 public int x { get; set; }
171 public int y { get; set; }
172 public int width { get; set; }
173 public int height { get; set; }
174 public WindowState state { get; set; }
175
176 GLib.Settings settings;
177
178 public string key_name;
179
180 /**
181 * Writes the values to the gsettings-backend.
182 */
183 public void write () {
184 GLib.Variant v_x = new GLib.Variant.int32 (x);
185 GLib.Variant v_y = new GLib.Variant.int32 (y);
186 GLib.Variant v_width = new GLib.Variant.int32 (width);
187 GLib.Variant v_height = new GLib.Variant.int32 (height);
188 GLib.Variant v_state = new GLib.Variant.uint32 ((uint32) state);
189 message (state.to_string ());
190 // Tuple that contains the whole saved-state
191 GLib.Variant tuple = new GLib.Variant.tuple ({v_x, v_y, v_width, v_height, v_state});
192 settings.set_value (key_name, tuple);
193 }
194
195 private void read () {
196 GLib.Variant saved_state = settings.get_value (key_name);
197 int out_x, out_y, out_w, out_h;
198 uint out_state;
199 saved_state.get ("(iiiiu)",
200 out out_x,
201 out out_y,
202 out out_w,
203 out out_h,
204 out out_state);
205
206 // Check that we got a valid enum-value
207 if (out_state > 3)
208 out_state = 0;
209
210 x = out_x;
211 y = out_y;
212 width = out_w;
213 height = out_h;
214 state = (WindowState) out_state;
215
216 }
217
218 public SavedStateBackend (string schema, string key_name) {
219 this.key_name = key_name;
220 settings = new GLib.Settings (schema);
221 read ();
222 }
223 }
224
225 }
226
227}

Subscribers

People subscribed via source and target branches