mirror of
https://github.com/elementary/gala.git
synced 2024-08-17 02:50:38 +03:00
Remember window position (#1751)
Co-authored-by: Corentin Noël <tintou@noel.tf> Co-authored-by: Danielle Foré <danielle@elementary.io> Co-authored-by: Ryan Kornheisl <ryan@skarva.tech>
This commit is contained in:
parent
4d70c8e3c5
commit
72b9e012f3
2
.github/workflows/main.yml
vendored
2
.github/workflows/main.yml
vendored
@ -31,7 +31,7 @@ jobs:
|
|||||||
- name: Install Dependencies
|
- name: Install Dependencies
|
||||||
run: |
|
run: |
|
||||||
apt update
|
apt update
|
||||||
apt install -y gettext gnome-settings-daemon-dev gsettings-desktop-schemas-dev libbamf3-dev libcanberra-dev libcanberra-gtk3-dev libclutter-1.0-dev libgee-0.8-dev libglib2.0-dev libgnome-desktop-3-dev libgranite-dev libgtk-3-dev ${{ matrix.mutter_pkg }} libplank-dev libxml2-utils libgexiv2-dev meson valac valadoc
|
apt install -y gettext gnome-settings-daemon-dev gsettings-desktop-schemas-dev libbamf3-dev libcanberra-dev libcanberra-gtk3-dev libclutter-1.0-dev libgee-0.8-dev libglib2.0-dev libgnome-desktop-3-dev libgranite-dev libgtk-3-dev ${{ matrix.mutter_pkg }} libplank-dev libxml2-utils libgexiv2-dev libsqlite3-dev meson valac valadoc
|
||||||
- name: Build
|
- name: Build
|
||||||
env:
|
env:
|
||||||
DESTDIR: out
|
DESTDIR: out
|
||||||
|
@ -97,6 +97,7 @@ gsd_dep = dependency('gnome-settings-daemon', version: '>= @0@'.format(gsd_versi
|
|||||||
m_dep = cc.find_library('m', required: false)
|
m_dep = cc.find_library('m', required: false)
|
||||||
posix_dep = vala.find_library('posix', required: false)
|
posix_dep = vala.find_library('posix', required: false)
|
||||||
gexiv2_dep = dependency('gexiv2')
|
gexiv2_dep = dependency('gexiv2')
|
||||||
|
sqlite3_dep = dependency('sqlite3')
|
||||||
if get_option('systemd')
|
if get_option('systemd')
|
||||||
systemd_dep = dependency('libsystemd')
|
systemd_dep = dependency('libsystemd')
|
||||||
endif
|
endif
|
||||||
@ -163,7 +164,7 @@ endif
|
|||||||
add_project_arguments(vala_flags, language: 'vala')
|
add_project_arguments(vala_flags, language: 'vala')
|
||||||
add_project_link_arguments(['-Wl,-rpath,@0@'.format(mutter_typelib_dir)], language: 'c')
|
add_project_link_arguments(['-Wl,-rpath,@0@'.format(mutter_typelib_dir)], language: 'c')
|
||||||
|
|
||||||
gala_base_dep = [canberra_dep, glib_dep, gobject_dep, gio_dep, gio_unix_dep, gmodule_dep, gee_dep, gtk_dep, mutter_dep, granite_dep, gnome_desktop_dep, m_dep, posix_dep, gexiv2_dep, config_dep]
|
gala_base_dep = [canberra_dep, glib_dep, gobject_dep, gio_dep, gio_unix_dep, gmodule_dep, gee_dep, gtk_dep, mutter_dep, granite_dep, gnome_desktop_dep, m_dep, posix_dep, gexiv2_dep, sqlite3_dep, config_dep]
|
||||||
|
|
||||||
if get_option('systemd')
|
if get_option('systemd')
|
||||||
gala_base_dep += systemd_dep
|
gala_base_dep += systemd_dep
|
||||||
|
@ -187,6 +187,7 @@ namespace Gala {
|
|||||||
WindowListener.init (display);
|
WindowListener.init (display);
|
||||||
KeyboardManager.init (display);
|
KeyboardManager.init (display);
|
||||||
window_tracker = new WindowTracker ();
|
window_tracker = new WindowTracker ();
|
||||||
|
WindowStateSaver.init (window_tracker);
|
||||||
window_tracker.init (display);
|
window_tracker.init (display);
|
||||||
|
|
||||||
notification_stack = new NotificationStack (display);
|
notification_stack = new NotificationStack (display);
|
||||||
@ -1436,6 +1437,8 @@ namespace Gala {
|
|||||||
public override void map (Meta.WindowActor actor) {
|
public override void map (Meta.WindowActor actor) {
|
||||||
unowned var window = actor.get_meta_window ();
|
unowned var window = actor.get_meta_window ();
|
||||||
|
|
||||||
|
WindowStateSaver.on_map (window);
|
||||||
|
|
||||||
if ((window.maximized_horizontally && behavior_settings.get_boolean ("move-maximized-workspace")) ||
|
if ((window.maximized_horizontally && behavior_settings.get_boolean ("move-maximized-workspace")) ||
|
||||||
(window.fullscreen && window.is_on_primary_monitor () && behavior_settings.get_boolean ("move-fullscreened-workspace"))) {
|
(window.fullscreen && window.is_on_primary_monitor () && behavior_settings.get_boolean ("move-fullscreened-workspace"))) {
|
||||||
move_window_to_next_ws (window);
|
move_window_to_next_ws (window);
|
||||||
|
164
src/WindowStateSaver.vala
Normal file
164
src/WindowStateSaver.vala
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 elementary, Inc. <https://elementary.io>
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class Gala.WindowStateSaver : GLib.Object {
|
||||||
|
private static unowned WindowTracker window_tracker;
|
||||||
|
private static GLib.HashTable<string, GLib.Array<Meta.Window?>> app_windows;
|
||||||
|
private static Sqlite.Database db;
|
||||||
|
|
||||||
|
public static void init (WindowTracker window_tracker) {
|
||||||
|
WindowStateSaver.window_tracker = window_tracker;
|
||||||
|
app_windows = new GLib.HashTable<string, GLib.Array<Meta.Window?>> (GLib.str_hash, GLib.str_equal);
|
||||||
|
|
||||||
|
var dir = Path.build_filename (GLib.Environment.get_user_data_dir (), "io.elementary.gala");
|
||||||
|
Posix.mkdir (dir, 0775);
|
||||||
|
var path = Path.build_filename (dir, "windowstate.db");
|
||||||
|
var rc = Sqlite.Database.open_v2 (path, out db);
|
||||||
|
|
||||||
|
if (rc != Sqlite.OK) {
|
||||||
|
critical ("Cannot open database: %d, %s", rc, db.errmsg ());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Sqlite.Statement stmt;
|
||||||
|
rc = db.prepare_v2 (
|
||||||
|
"""
|
||||||
|
CREATE TABLE IF NOT EXISTS apps (
|
||||||
|
app_id TEXT,
|
||||||
|
window_index INTEGER,
|
||||||
|
last_x INTEGER,
|
||||||
|
last_y INTEGER,
|
||||||
|
last_width INTEGER,
|
||||||
|
last_height INTEGER,
|
||||||
|
PRIMARY KEY (app_id, window_index)
|
||||||
|
);
|
||||||
|
""",
|
||||||
|
-1, out stmt
|
||||||
|
);
|
||||||
|
|
||||||
|
if (rc == Sqlite.OK) {
|
||||||
|
rc = stmt.step ();
|
||||||
|
if (rc == Sqlite.DONE) {
|
||||||
|
// disable synchronized commits for performance reasons
|
||||||
|
rc = db.exec ("PRAGMA synchronous=OFF");
|
||||||
|
if (rc != Sqlite.OK) {
|
||||||
|
warning ("Unable to disable synchronous mode %d, %s", rc, db.errmsg ());
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
critical ("Cannot create table 'apps': %d, %s", rc, db.errmsg ());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void on_map (Meta.Window window) {
|
||||||
|
var app_id = GLib.Markup.escape_text (window_tracker.get_app_for_window (window).id);
|
||||||
|
|
||||||
|
if (app_id.has_prefix ("window:")) {
|
||||||
|
// if window failed to be identified, don't remember it
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window.window_type != Meta.WindowType.NORMAL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(app_id in app_windows)) {
|
||||||
|
app_windows[app_id] = new GLib.Array<Meta.Window?> ();
|
||||||
|
}
|
||||||
|
|
||||||
|
var window_index = find_window_index (window, app_id);
|
||||||
|
app_windows[app_id].insert_val (window_index, window);
|
||||||
|
|
||||||
|
var tracking_window = false;
|
||||||
|
db.exec (
|
||||||
|
"SELECT last_x, last_y, last_width, last_height FROM apps WHERE app_id = '%s' AND window_index = '%d';".printf (app_id, window_index),
|
||||||
|
(n_columns, values, column_names) => {
|
||||||
|
window.move_resize_frame (false, int.parse (values[0]), int.parse (values[1]), int.parse (values[2]), int.parse (values[3]));
|
||||||
|
track_window (window, app_id);
|
||||||
|
tracking_window = true;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (tracking_window) {
|
||||||
|
// App was added in callback
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var frame_rect = window.get_frame_rect ();
|
||||||
|
|
||||||
|
Sqlite.Statement stmt;
|
||||||
|
var rc = db.prepare_v2 (
|
||||||
|
"INSERT INTO apps (app_id, window_index, last_x, last_y, last_width, last_height) VALUES ('%s', '%d', '%d', '%d', '%d', '%d');"
|
||||||
|
.printf (app_id, window_index, frame_rect.x, frame_rect.y, frame_rect.width, frame_rect.height),
|
||||||
|
-1, out stmt
|
||||||
|
);
|
||||||
|
|
||||||
|
if (rc == Sqlite.OK) {
|
||||||
|
rc = stmt.step ();
|
||||||
|
if (rc == Sqlite.DONE) {
|
||||||
|
track_window (window, app_id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
critical ("Cannot insert app information into database: %d, %s", rc, db.errmsg ());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void track_window (Meta.Window window, string app_id) {
|
||||||
|
window.unmanaging.connect (on_window_unmanaging);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void on_window_unmanaging (Meta.Window window) {
|
||||||
|
var app_id = GLib.Markup.escape_text (window_tracker.get_app_for_window (window).id);
|
||||||
|
|
||||||
|
var window_index = find_window_index (window, app_id);
|
||||||
|
app_windows[app_id].remove_index (window_index);
|
||||||
|
var value = null; // insert_val requires lvalue
|
||||||
|
app_windows[app_id].insert_val (window_index, value);
|
||||||
|
|
||||||
|
var frame_rect = window.get_frame_rect ();
|
||||||
|
|
||||||
|
Sqlite.Statement stmt;
|
||||||
|
var rc = db.prepare_v2 (
|
||||||
|
"UPDATE apps SET last_x = '%d', last_y = '%d', last_width = '%d', last_height = '%d' WHERE app_id = '%s' AND window_index = '%d';"
|
||||||
|
.printf (frame_rect.x, frame_rect.y, frame_rect.width, frame_rect.height, app_id, window_index),
|
||||||
|
-1, out stmt
|
||||||
|
);
|
||||||
|
|
||||||
|
if (rc == Sqlite.OK) {
|
||||||
|
rc = stmt.step ();
|
||||||
|
if (rc == Sqlite.DONE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
critical ("Cannot update app position in database: %d, %s", rc, db.errmsg ());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int find_window_index (Meta.Window window, string app_id) requires (app_id in app_windows) {
|
||||||
|
unowned var windows_list = app_windows[app_id];
|
||||||
|
var first_null = -1;
|
||||||
|
for (int i = 0; i < windows_list.length; i++) {
|
||||||
|
var w = windows_list.data[i];
|
||||||
|
if (w == window) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (w == null && first_null == -1) {
|
||||||
|
first_null = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (first_null != -1) {
|
||||||
|
return first_null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int) windows_list.length;
|
||||||
|
}
|
||||||
|
}
|
@ -15,6 +15,7 @@ gala_bin_sources = files(
|
|||||||
'SessionManager.vala',
|
'SessionManager.vala',
|
||||||
'WindowListener.vala',
|
'WindowListener.vala',
|
||||||
'WindowManager.vala',
|
'WindowManager.vala',
|
||||||
|
'WindowStateSaver.vala',
|
||||||
'WindowTracker.vala',
|
'WindowTracker.vala',
|
||||||
'WorkspaceManager.vala',
|
'WorkspaceManager.vala',
|
||||||
'Zoom.vala',
|
'Zoom.vala',
|
||||||
|
Loading…
Reference in New Issue
Block a user