├── .editorconfig ├── .github ├── dependabot.yml └── workflows │ ├── gettext.yml │ ├── main.yml │ └── release.yml ├── .gitignore ├── AUTHORS ├── COPYING ├── HACKING ├── README.md ├── build-aux ├── git-version-gen └── gitlog-to-changelog ├── daemon-gtk3 ├── BackgroundMenu.vala ├── DBus.vala ├── Main.vala ├── MonitorLabel.vala ├── Window.vala ├── WindowMenu.vala └── meson.build ├── daemon ├── DBus.vala ├── DisplayConfig.vala ├── Main.vala ├── MonitorLabel.vala ├── Window.vala ├── WindowMenu.vala └── meson.build ├── data ├── 20_elementary.pantheon.wm.gschema.override ├── close.svg ├── gala-daemon.css ├── gala-multitaskingview.desktop.in ├── gala-other.desktop.in ├── gala-wayland.desktop ├── gala.desktop ├── gala.gresource.xml ├── gala.gschema.xml ├── gala.metainfo.xml.in ├── gala.target ├── gala@wayland.service.in ├── gala@x11.service.in ├── io.elementary.desktop.wm.shell ├── meson.build ├── resize.svg └── shaders │ ├── colorblindness-correction.vert │ └── monochrome.vert ├── docs └── meson.build ├── lib ├── ActivatableComponent.vala ├── App.vala ├── AppCache.vala ├── AppSystem.vala ├── BackgroundManager.vala ├── CanvasActor.vala ├── CloseButton.vala ├── Constants.vala ├── DragDropAction.vala ├── Drawing │ ├── BufferSurface.vala │ ├── Canvas.vala │ ├── Color.vala │ ├── StyleManager.vala │ └── Utilities.vala ├── Plugin.vala ├── ShadowEffect.vala ├── Utils.vala ├── WindowIcon.vala ├── WindowManager.vala ├── gala.deps.in └── meson.build ├── meson.build ├── meson_options.txt ├── plugins ├── pip │ ├── Main.vala │ ├── PopupWindow.vala │ ├── SelectionArea.vala │ └── meson.build └── template │ ├── Main.vala │ ├── README │ └── meson.build ├── po ├── LINGUAS ├── POTFILES ├── aa.po ├── ab.po ├── ace.po ├── ae.po ├── af.po ├── ak.po ├── am.po ├── an.po ├── ar.po ├── as.po ├── ast.po ├── av.po ├── ay.po ├── az.po ├── ba.po ├── be.po ├── bg.po ├── bh.po ├── bi.po ├── bm.po ├── bn.po ├── bo.po ├── br.po ├── bs.po ├── ca.po ├── ca@valencia.po ├── ce.po ├── ch.po ├── ckb.po ├── co.po ├── cr.po ├── cs.po ├── cu.po ├── cv.po ├── cy.po ├── da.po ├── de.po ├── dv.po ├── dz.po ├── ee.po ├── el.po ├── en_AU.po ├── en_CA.po ├── en_GB.po ├── en_ZA.po ├── eo.po ├── es.po ├── et.po ├── eu.po ├── fa.po ├── ff.po ├── fi.po ├── fil.po ├── fj.po ├── fo.po ├── fr.po ├── fr_CA.po ├── frp.po ├── fy.po ├── ga.po ├── gala.pot ├── gd.po ├── gl.po ├── gn.po ├── gu.po ├── gv.po ├── ha.po ├── he.po ├── hi.po ├── ho.po ├── hr.po ├── ht.po ├── hu.po ├── hy.po ├── hz.po ├── ia.po ├── id.po ├── id_ID.po ├── ie.po ├── ig.po ├── ii.po ├── ik.po ├── io.po ├── is.po ├── it.po ├── iu.po ├── ja.po ├── jv.po ├── ka.po ├── kg.po ├── ki.po ├── kj.po ├── kk.po ├── kl.po ├── km.po ├── kn.po ├── ko.po ├── kr.po ├── ks.po ├── ku.po ├── kv.po ├── kw.po ├── ky.po ├── la.po ├── lb.po ├── lg.po ├── li.po ├── ln.po ├── lo.po ├── lt.po ├── lu.po ├── lv.po ├── meson.build ├── mg.po ├── mh.po ├── mi.po ├── mk.po ├── ml.po ├── mn.po ├── mo.po ├── mr.po ├── ms.po ├── mt.po ├── my.po ├── na.po ├── nb.po ├── nd.po ├── ne.po ├── ng.po ├── nl.po ├── nn.po ├── no.po ├── nr.po ├── nv.po ├── ny.po ├── oc.po ├── oj.po ├── om.po ├── or.po ├── os.po ├── pa.po ├── pap.po ├── pi.po ├── pl.po ├── ps.po ├── pt.po ├── pt_BR.po ├── qu.po ├── rm.po ├── rn.po ├── ro.po ├── ru.po ├── rue.po ├── rw.po ├── sa.po ├── sc.po ├── sco.po ├── sd.po ├── se.po ├── sg.po ├── si.po ├── sk.po ├── sl.po ├── sm.po ├── sma.po ├── sn.po ├── so.po ├── sq.po ├── sr.po ├── sr@latin.po ├── ss.po ├── st.po ├── su.po ├── sv.po ├── sw.po ├── szl.po ├── ta.po ├── te.po ├── tg.po ├── th.po ├── ti.po ├── tk.po ├── tl.po ├── tn.po ├── to.po ├── tr.po ├── ts.po ├── tt.po ├── tw.po ├── ty.po ├── ug.po ├── uk.po ├── ur.po ├── uz.po ├── ve.po ├── vi.po ├── vo.po ├── wa.po ├── wo.po ├── xh.po ├── yi.po ├── yo.po ├── za.po ├── zh.po ├── zh_CN.po ├── zh_HK.po ├── zh_TW.po └── zu.po ├── protocol ├── meson.build ├── pantheon-desktop-shell-v1.xml ├── pantheon-desktop-shell.deps └── pantheon-desktop-shell.vapi ├── src ├── Background │ ├── Animation.vala │ ├── Background.vala │ ├── BackgroundCache.vala │ ├── BackgroundContainer.vala │ ├── BackgroundManager.vala │ ├── BackgroundSource.vala │ ├── BlurEffect.vala │ └── SystemBackground.vala ├── ColorFilters │ ├── ColorblindnessCorrectionEffect.vala │ ├── FilterManager.vala │ └── MonochromeEffect.vala ├── DBus.vala ├── DBusAccelerator.vala ├── DaemonManager.vala ├── DesktopIntegration.vala ├── Dialogs │ ├── AccessDialog.vala │ ├── CloseDialog.vala │ └── InhibitShortcutsDialog.vala ├── Gestures │ ├── ActorTarget.vala │ ├── Gesture.vala │ ├── GestureBackend.vala │ ├── GestureController.vala │ ├── GestureSettings.vala │ ├── GestureTarget.vala │ ├── PropertyTarget.vala │ ├── RootTarget.vala │ ├── ScrollBackend.vala │ ├── SpringTimeline.vala │ └── ToucheggBackend.vala ├── HotCorners │ ├── Barrier.vala │ ├── HotCorner.vala │ └── HotCornerManager.vala ├── InternalUtils.vala ├── KeyboardManager.vala ├── Main.vala ├── NotificationStack.vala ├── NotificationsManager.vala ├── PantheonShell.vala ├── PluginManager.vala ├── ScreenSaverManager.vala ├── ScreenshotManager.vala ├── SessionManager.vala ├── ShellClients │ ├── HideTracker.vala │ ├── ManagedClient.vala │ ├── NotificationsClient.vala │ ├── PanelWindow.vala │ ├── PositionedWindow.vala │ ├── ShellClientsManager.vala │ └── ShellWindow.vala ├── SuperScrollAction.vala ├── Widgets │ ├── DwellClickTimer.vala │ ├── MultitaskingView │ │ ├── IconGroup.vala │ │ ├── IconGroupContainer.vala │ │ ├── MonitorClone.vala │ │ ├── MultitaskingView.vala │ │ ├── StaticWindowClone.vala │ │ ├── StaticWindowContainer.vala │ │ ├── Tooltip.vala │ │ ├── WindowClone.vala │ │ ├── WindowCloneContainer.vala │ │ ├── WindowIconActor.vala │ │ ├── WorkspaceClone.vala │ │ ├── WorkspaceInsertThumb.vala │ │ └── WorkspaceRow.vala │ ├── PixelPicker.vala │ ├── PointerLocator.vala │ ├── SelectionArea.vala │ ├── SessionLocker.vala │ ├── WindowOverview.vala │ └── WindowSwitcher │ │ ├── WindowSwitcher.vala │ │ └── WindowSwitcherIcon.vala ├── WindowListener.vala ├── WindowManager.vala ├── WindowStateSaver.vala ├── WindowTracker.vala ├── WorkspaceManager.vala ├── Zoom.vala └── meson.build ├── tools └── remove_mutter_versions.py └── vapi ├── Clutter-13-custom.vala ├── Clutter-13.metadata ├── Clutter-14-custom.vala ├── Clutter-14.metadata ├── Clutter-15-custom.vala ├── Clutter-15.metadata ├── Cogl-13-custom.vala ├── Cogl-13.metadata ├── Cogl-14-custom.vala ├── Cogl-14.metadata ├── Cogl-15-custom.vala ├── Cogl-15.metadata ├── Meta-13.metadata ├── Meta-14.metadata ├── Meta-15.metadata ├── Mtk-13.metadata ├── Mtk-14.metadata ├── Mtk-15.metadata ├── atk-bridge-2.0.vapi ├── config.vapi ├── gdesktopenums-3.0.vapi ├── gnome-desktop-3.0.deps ├── gnome-desktop-3.0.vapi ├── libmutter-13.deps ├── libmutter-13.vapi ├── libmutter-14.deps ├── libmutter-14.vapi ├── libmutter-15.deps ├── libmutter-15.vapi ├── libmutter.deps ├── libmutter.vapi ├── libsystemd.vapi ├── meson.build ├── mutter-clutter-13.deps ├── mutter-clutter-13.vapi ├── mutter-clutter-14.deps ├── mutter-clutter-14.vapi ├── mutter-clutter-15.deps ├── mutter-clutter-15.vapi ├── mutter-clutter.vapi ├── mutter-cogl-13.deps ├── mutter-cogl-13.vapi ├── mutter-cogl-14.deps ├── mutter-cogl-14.vapi ├── mutter-cogl-15.deps ├── mutter-cogl-15.vapi ├── mutter-cogl-pango-13.vapi ├── mutter-cogl-pango-14.vapi ├── mutter-cogl-pango-15.vapi ├── mutter-cogl-pango.vapi ├── mutter-cogl.deps ├── mutter-cogl.vapi ├── mutter-mtk-13.vapi ├── mutter-mtk-14.vapi ├── mutter-mtk-15.vapi ├── wayland-server.deps ├── wayland-server.vapi └── xfixes-4.0.vapi /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig 2 | root = true 3 | 4 | # elementary defaults 5 | [*] 6 | charset = utf-8 7 | end_of_line = lf 8 | indent_size = tab 9 | indent_style = space 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | max_line_length = 80 13 | tab_width = 4 14 | 15 | [{*.xml,*.xml.in,*.yml}] 16 | tab_width = 2 17 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | -------------------------------------------------------------------------------- /.github/workflows/gettext.yml: -------------------------------------------------------------------------------- 1 | name: Gettext Updates 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-22.04 10 | container: 11 | image: ghcr.io/elementary/docker:next-unstable 12 | 13 | steps: 14 | - name: Install git 15 | run: | 16 | apt-get update 17 | apt-get install git -y 18 | 19 | - name: Clone repository 20 | uses: actions/checkout@v4 21 | with: 22 | token: ${{ secrets.GIT_USER_TOKEN }} 23 | 24 | - name: Update Translation Files 25 | uses: elementary/actions/gettext-template@main 26 | env: 27 | GIT_USER_TOKEN: ${{ secrets.GIT_USER_TOKEN }} 28 | GIT_USER_NAME: "elementaryBot" 29 | GIT_USER_EMAIL: "builds@elementary.io" 30 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | pull_request: 5 | types: 6 | - opened 7 | - reopened 8 | - synchronize 9 | 10 | jobs: 11 | build: 12 | 13 | runs-on: ubuntu-22.04 14 | 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | version: [stable, unstable, development-target] 19 | include: 20 | - version: stable 21 | mutter_pkg: libmutter-14-dev 22 | - version: unstable 23 | mutter_pkg: libmutter-14-dev 24 | - version: development-target 25 | mutter_pkg: libmutter-14-dev 26 | container: 27 | image: ghcr.io/elementary/docker:${{ matrix.version }} 28 | 29 | steps: 30 | - uses: actions/checkout@v4 31 | - name: Install Dependencies 32 | run: | 33 | apt update 34 | apt install -y gettext gsettings-desktop-schemas-dev libatk-bridge2.0-dev libcanberra-dev libclutter-1.0-dev libgee-0.8-dev libglib2.0-dev libgnome-desktop-3-dev libgranite-dev libgtk-3-dev ${{ matrix.mutter_pkg }} libxml2-utils libsqlite3-dev meson valac valadoc 35 | - name: Build 36 | env: 37 | DESTDIR: out 38 | run: | 39 | meson build -Ddocumentation=true 40 | ninja -C build 41 | ninja -C build install 42 | 43 | fedora: 44 | runs-on: ubuntu-latest 45 | 46 | container: 47 | image: fedora:latest 48 | 49 | steps: 50 | - uses: actions/checkout@v4 51 | - name: Install Dependencies 52 | run: | 53 | dnf install -y desktop-file-utils gettext gsettings-desktop-schemas-devel atk-devel libcanberra-devel clutter-devel libgee-devel glib2-devel gnome-desktop3-devel granite-devel granite-7-devel gtk3-devel gtk4-devel libhandy-devel mutter-devel xml2 sqlite-devel meson valac valadoc 54 | - name: Build 55 | env: 56 | DESTDIR: out 57 | run: | 58 | meson build 59 | ninja -C build install 60 | 61 | lint: 62 | 63 | runs-on: ubuntu-latest 64 | 65 | container: 66 | image: valalang/lint 67 | 68 | steps: 69 | - uses: actions/checkout@v4 70 | - name: Lint 71 | run: | 72 | io.elementary.vala-lint -d daemon 73 | io.elementary.vala-lint -d lib 74 | io.elementary.vala-lint -d plugins 75 | io.elementary.vala-lint -d src 76 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | pull_request: 5 | branches: [main] 6 | types: [closed] 7 | 8 | jobs: 9 | release: 10 | runs-on: ubuntu-22.04 11 | if: github.event.pull_request.merged == true && true == contains(join(github.event.pull_request.labels.*.name), 'Release') 12 | steps: 13 | - uses: actions/checkout@v4 14 | - uses: elementary/actions/release@master 15 | env: 16 | GIT_USER_TOKEN: "${{ secrets.GIT_USER_TOKEN }}" 17 | GIT_USER_NAME: "elementaryBot" 18 | GIT_USER_EMAIL: "builds@elementary.io" 19 | with: 20 | release_branch: 'noble' 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ABOUT-NLS 2 | aclocal.m4 3 | autom4te.cache 4 | /build-aux/* 5 | ChangeLog 6 | config.h 7 | config.h.in 8 | config.h.in~ 9 | config.log 10 | config.status 11 | configure 12 | libtool 13 | m4 14 | mkinstalldirs 15 | stamp-h1 16 | Makefile 17 | Makefile.in 18 | .version 19 | .deps 20 | .dirstamp 21 | .libs 22 | *.c 23 | *.h 24 | *.lo 25 | *.la 26 | *.o 27 | *.pc 28 | *.stamp 29 | data/gala.desktop 30 | data/gala-multitaskingview.desktop 31 | data/gala-other.desktop 32 | data/gschemas.compiled 33 | data/org.pantheon.desktop.gala.gschema.valid 34 | data/org.pantheon.desktop.gala.gschema.xml 35 | data/org.pantheon.desktop.gala.gschema.xml.in 36 | docs/gala 37 | docs/libgala 38 | lib/gala.vapi 39 | po/*.gmo 40 | po/*.header 41 | po/*.sed 42 | po/*.sin 43 | po/Makefile.in.in 44 | po/Makevars.template 45 | po/POTFILES 46 | po/Rules-quot 47 | po/stamp-po 48 | src/gala 49 | build 50 | debian 51 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Cody Garver 2 | Daniel Fore 3 | Garden Gnome 4 | Niels Avonds 5 | Rico Tzschichholz 6 | Sergey "Shnatsel" Davidoff 7 | Timo Reimerdes 8 | Tom Beckmann 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Gala 2 | [![Translation status](https://l10n.elementary.io/widgets/desktop/-/gala/svg-badge.svg)](https://l10n.elementary.io/engage/desktop/?utm_source=widget) 3 | 4 | A window & compositing manager based on libmutter and designed by elementary for use with Pantheon. 5 | 6 | ## Building, Testing, and Installation 7 | 8 | You'll need the following dependencies: 9 | * gettext (>= 0.19.6) 10 | * gsettings-desktop-schemas-dev 11 | * libcanberra-dev 12 | * libclutter-1.0-dev (>= 1.12.0) 13 | * libgee-0.8-dev 14 | * libglib2.0-dev (>= 2.74) 15 | * libgnome-desktop-3-dev 16 | * libgranite-dev (>= 5.4.0) 17 | * libgtk-3-dev (>= 3.10.0) 18 | * libmutter-10-dev (>= 42.0) | libmutter-dev (>= 3.18.3) 19 | * libxml2-utils 20 | * meson (>= 0.59.0) 21 | * valac (>= 0.46.0) 22 | 23 | Run `meson build` to configure the build environment. Change to the build directory and run `ninja` to build 24 | 25 | meson build --prefix=/usr 26 | cd build 27 | ninja 28 | 29 | You can set the `documentation` option to `true` to build the documentation. In the build directory, use `meson configure` 30 | 31 | meson configure -Ddocumentation=true 32 | 33 | To install, use `ninja install`, then execute with `gala --replace` 34 | 35 | sudo ninja install 36 | gala --replace 37 | -------------------------------------------------------------------------------- /daemon-gtk3/BackgroundMenu.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 elementary, Inc. (https://elementary.io) 3 | * SPDX-License-Identifier: GPL-3.0-or-later 4 | */ 5 | 6 | public class Gala.Daemon.BackgroundMenu : Gtk.Menu { 7 | public const string ACTION_GROUP_PREFIX = "background-menu"; 8 | public const string ACTION_PREFIX = ACTION_GROUP_PREFIX + "."; 9 | 10 | construct { 11 | var change_wallpaper = new Gtk.MenuItem.with_label (_("Change Wallpaper…")) { 12 | action_name = ACTION_PREFIX + "launch-uri", 13 | action_target = new Variant.string ("settings://desktop/appearance/wallpaper") 14 | }; 15 | 16 | var display_settings = new Gtk.MenuItem.with_label (_("Display Settings…")) { 17 | action_name = ACTION_PREFIX + "launch-uri", 18 | action_target = new Variant.string ("settings://display") 19 | }; 20 | 21 | 22 | var system_settings = new Gtk.MenuItem.with_label (_("System Settings…")) { 23 | action_name = ACTION_PREFIX + "launch-uri", 24 | action_target = new Variant.string ("settings://") 25 | }; 26 | 27 | append (change_wallpaper); 28 | append (display_settings); 29 | append (new Gtk.SeparatorMenuItem ()); 30 | append (system_settings); 31 | show_all (); 32 | 33 | var launch_action = new SimpleAction ("launch-uri", VariantType.STRING); 34 | launch_action.activate.connect (action_launch); 35 | 36 | var action_group = new SimpleActionGroup (); 37 | action_group.add_action (launch_action); 38 | 39 | insert_action_group (ACTION_GROUP_PREFIX, action_group); 40 | } 41 | 42 | private void action_launch (SimpleAction action, Variant? variant) { 43 | try { 44 | AppInfo.launch_default_for_uri (variant.get_string (), null); 45 | } catch (Error e) { 46 | var message_dialog = new Granite.MessageDialog.with_image_from_icon_name ( 47 | _("Failed to open System Settings"), 48 | _("A handler for the “settings://” URI scheme must be installed."), 49 | "dialog-error", 50 | Gtk.ButtonsType.CLOSE 51 | ); 52 | message_dialog.show_error_details (e.message); 53 | message_dialog.present (); 54 | message_dialog.response.connect (message_dialog.destroy); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /daemon-gtk3/Main.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 elementary, Inc. (https://elementary.io) 3 | * SPDX-License-Identifier: GPL-3.0-or-later 4 | */ 5 | 6 | public class Gala.Daemon.Application : Gtk.Application { 7 | public Application () { 8 | Object (application_id: "org.pantheon.gala.daemon"); 9 | } 10 | 11 | public override void startup () { 12 | base.startup (); 13 | 14 | var granite_settings = Granite.Settings.get_default (); 15 | var gtk_settings = Gtk.Settings.get_default (); 16 | 17 | gtk_settings.gtk_application_prefer_dark_theme = granite_settings.prefers_color_scheme == Granite.Settings.ColorScheme.DARK; 18 | 19 | granite_settings.notify["prefers-color-scheme"].connect (() => { 20 | gtk_settings.gtk_application_prefer_dark_theme = granite_settings.prefers_color_scheme == Granite.Settings.ColorScheme.DARK; 21 | }); 22 | 23 | var app_provider = new Gtk.CssProvider (); 24 | app_provider.load_from_resource ("io/elementary/desktop/gala-daemon/gala-daemon.css"); 25 | Gtk.StyleContext.add_provider_for_screen (Gdk.Screen.get_default (), app_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); 26 | } 27 | 28 | public override void activate () { 29 | hold (); 30 | } 31 | 32 | public override bool dbus_register (DBusConnection connection, string object_path) throws Error { 33 | base.dbus_register (connection, object_path); 34 | 35 | connection.register_object (object_path, new DBus ()); 36 | 37 | return true; 38 | } 39 | } 40 | 41 | public static int main (string[] args) { 42 | GLib.Intl.setlocale (LocaleCategory.ALL, ""); 43 | GLib.Intl.bindtextdomain (Config.GETTEXT_PACKAGE, Config.LOCALEDIR); 44 | GLib.Intl.bind_textdomain_codeset (Config.GETTEXT_PACKAGE, "UTF-8"); 45 | GLib.Intl.textdomain (Config.GETTEXT_PACKAGE); 46 | 47 | var app = new Gala.Daemon.Application (); 48 | return app.run (); 49 | } 50 | -------------------------------------------------------------------------------- /daemon-gtk3/MonitorLabel.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 elementary, Inc. (https://elementary.io) 3 | * SPDX-License-Identifier: LGPL-3.0-or-later 4 | */ 5 | 6 | public class Gala.Daemon.MonitorLabel : Hdy.Window { 7 | private const int SPACING = 12; 8 | private const string COLORED_STYLE_CSS = """ 9 | .%s { 10 | background-color: alpha(%s, 0.8); 11 | color: %s; 12 | } 13 | """; 14 | 15 | public MonitorLabelInfo info { get; construct; } 16 | 17 | public MonitorLabel (MonitorLabelInfo info) { 18 | Object (info: info); 19 | } 20 | 21 | construct { 22 | child = new Gtk.Label (info.label); 23 | 24 | title = "LABEL-%i".printf (info.monitor); 25 | 26 | input_shape_combine_region (null); 27 | accept_focus = false; 28 | decorated = false; 29 | resizable = false; 30 | deletable = false; 31 | can_focus = false; 32 | skip_taskbar_hint = true; 33 | skip_pager_hint = true; 34 | type_hint = Gdk.WindowTypeHint.TOOLTIP; 35 | set_keep_above (true); 36 | 37 | stick (); 38 | 39 | var scale_factor = get_style_context ().get_scale (); 40 | move ( 41 | (int) (info.x / scale_factor) + SPACING, 42 | (int) (info.y / scale_factor) + SPACING 43 | ); 44 | 45 | var provider = new Gtk.CssProvider (); 46 | try { 47 | provider.load_from_data (COLORED_STYLE_CSS.printf (title, info.background_color, info.text_color)); 48 | get_style_context ().add_class (title); 49 | get_style_context ().add_class ("monitor-label"); 50 | 51 | Gtk.StyleContext.add_provider_for_screen ( 52 | Gdk.Screen.get_default (), 53 | provider, 54 | Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION 55 | ); 56 | } catch (Error e) { 57 | warning ("Failed to load CSS: %s", e.message); 58 | } 59 | 60 | show_all (); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /daemon-gtk3/Window.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 elementary, Inc. (https://elementary.io) 3 | * SPDX-License-Identifier: GPL-3.0-or-later 4 | * 5 | * Authored by: Leonhard Kargl 6 | */ 7 | 8 | public class Gala.Daemon.Window : Gtk.Window { 9 | public Gtk.Box content { get; construct; } 10 | 11 | public Window (int width, int height) { 12 | Object ( 13 | default_width: width, 14 | default_height: height 15 | ); 16 | } 17 | 18 | class construct { 19 | set_css_name ("daemon-window"); 20 | } 21 | 22 | construct { 23 | decorated = false; 24 | resizable = false; 25 | deletable = false; 26 | can_focus = false; 27 | input_shape_combine_region (null); 28 | accept_focus = false; 29 | skip_taskbar_hint = true; 30 | skip_pager_hint = true; 31 | type_hint = Gdk.WindowTypeHint.DOCK; 32 | set_keep_above (true); 33 | 34 | title = "MODAL"; 35 | child = content = new Gtk.Box (HORIZONTAL, 0) { 36 | hexpand = true, 37 | vexpand = true 38 | }; 39 | 40 | set_visual (get_screen ().get_rgba_visual ()); 41 | 42 | show_all (); 43 | move (0, 0); 44 | 45 | button_press_event.connect (() => { 46 | close (); 47 | return Gdk.EVENT_STOP; 48 | }); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /daemon-gtk3/meson.build: -------------------------------------------------------------------------------- 1 | gala_daemon_sources = files( 2 | 'Main.vala', 3 | 'DBus.vala', 4 | 'MonitorLabel.vala', 5 | 'Window.vala', 6 | 'WindowMenu.vala', 7 | 'BackgroundMenu.vala', 8 | ) 9 | 10 | granite_dep_old = dependency('granite') 11 | hdy_dep = dependency('libhandy-1') 12 | 13 | gala_daemon_bin = executable( 14 | 'gala-daemon-gtk3', 15 | gala_daemon_sources, 16 | dependencies: [gala_dep, gala_base_dep, granite_dep_old, hdy_dep], 17 | include_directories: config_inc_dir, 18 | install: true, 19 | ) 20 | -------------------------------------------------------------------------------- /daemon/DisplayConfig.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024-2025 elementary, Inc. (https://elementary.io) 3 | * SPDX-License-Identifier: GPL-3.0-or-later 4 | */ 5 | 6 | [DBus (name = "org.gnome.Mutter.DisplayConfig")] 7 | public interface Gala.Daemon.DisplayConfig : Object { 8 | private static bool? _is_logical_layout = null; 9 | private static DisplayConfig? proxy = null; 10 | 11 | public static bool is_logical_layout () { 12 | if (_is_logical_layout == null) { 13 | init (); 14 | } 15 | 16 | return _is_logical_layout; 17 | } 18 | 19 | private static void init () { 20 | try { 21 | proxy = Bus.get_proxy_sync (BusType.SESSION, "org.gnome.Mutter.DisplayConfig", "/org/gnome/Mutter/DisplayConfig"); 22 | proxy.monitors_changed.connect (update); 23 | } catch (Error e) { 24 | critical (e.message); 25 | _is_logical_layout = true; 26 | return; 27 | } 28 | 29 | update (); 30 | } 31 | 32 | private static void update () { 33 | uint current_serial; 34 | MutterReadMonitor[] mutter_monitors; 35 | MutterReadLogicalMonitor[] mutter_logical_monitors; 36 | GLib.HashTable properties; 37 | try { 38 | proxy.get_current_state (out current_serial, out mutter_monitors, out mutter_logical_monitors, out properties); 39 | } catch (Error e) { 40 | critical (e.message); 41 | _is_logical_layout = true; 42 | return; 43 | } 44 | 45 | uint layout_mode = 1; // Absence of "layout-mode" means logical (= 1) according to the documentation. 46 | var layout_mode_variant = properties.lookup ("layout-mode"); 47 | if (layout_mode_variant != null) { 48 | layout_mode = layout_mode_variant.get_uint32 (); 49 | } 50 | 51 | _is_logical_layout = layout_mode == 1; 52 | } 53 | 54 | public signal void monitors_changed (); 55 | public abstract void get_current_state (out uint serial, out MutterReadMonitor[] monitors, out MutterReadLogicalMonitor[] logical_monitors, out GLib.HashTable properties) throws Error; 56 | } 57 | 58 | public struct MutterReadMonitorInfo { 59 | public string connector; 60 | public string vendor; 61 | public string product; 62 | public string serial; 63 | public uint hash { 64 | get { 65 | return (connector + vendor + product + serial).hash (); 66 | } 67 | } 68 | } 69 | 70 | public struct MutterReadMonitorMode { 71 | public string id; 72 | public int width; 73 | public int height; 74 | public double frequency; 75 | public double preferred_scale; 76 | public double[] supported_scales; 77 | public GLib.HashTable properties; 78 | } 79 | 80 | public struct MutterReadMonitor { 81 | public MutterReadMonitorInfo monitor; 82 | public MutterReadMonitorMode[] modes; 83 | public GLib.HashTable properties; 84 | } 85 | 86 | public struct MutterReadLogicalMonitor { 87 | public int x; 88 | public int y; 89 | public double scale; 90 | public uint transform; 91 | public bool primary; 92 | public MutterReadMonitorInfo[] monitors; 93 | public GLib.HashTable properties; 94 | } 95 | -------------------------------------------------------------------------------- /daemon/Main.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 elementary, Inc. (https://elementary.io) 3 | * SPDX-License-Identifier: GPL-3.0-or-later 4 | */ 5 | 6 | public class Gala.Daemon.Application : Gtk.Application { 7 | public Application () { 8 | Object (application_id: "org.pantheon.gala.daemon"); 9 | } 10 | 11 | public override void startup () { 12 | base.startup (); 13 | 14 | var granite_settings = Granite.Settings.get_default (); 15 | var gtk_settings = Gtk.Settings.get_default (); 16 | 17 | gtk_settings.gtk_application_prefer_dark_theme = granite_settings.prefers_color_scheme == Granite.Settings.ColorScheme.DARK; 18 | 19 | granite_settings.notify["prefers-color-scheme"].connect (() => { 20 | gtk_settings.gtk_application_prefer_dark_theme = granite_settings.prefers_color_scheme == Granite.Settings.ColorScheme.DARK; 21 | }); 22 | 23 | var app_provider = new Gtk.CssProvider (); 24 | app_provider.load_from_resource ("/io/elementary/desktop/gala-daemon/gala-daemon.css"); 25 | Gtk.StyleContext.add_provider_for_display (Gdk.Display.get_default (), app_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); 26 | } 27 | 28 | public override void activate () { 29 | hold (); 30 | } 31 | 32 | public override bool dbus_register (DBusConnection connection, string object_path) throws Error { 33 | base.dbus_register (connection, object_path); 34 | 35 | // We are using gtk in the DBus () constructor so we need to init it early 36 | Gtk.init (); 37 | 38 | connection.register_object (object_path, new DBus ()); 39 | 40 | return true; 41 | } 42 | } 43 | 44 | public static int main (string[] args) { 45 | GLib.Intl.setlocale (LocaleCategory.ALL, ""); 46 | GLib.Intl.bindtextdomain (Config.GETTEXT_PACKAGE, Config.LOCALEDIR); 47 | GLib.Intl.bind_textdomain_codeset (Config.GETTEXT_PACKAGE, "UTF-8"); 48 | GLib.Intl.textdomain (Config.GETTEXT_PACKAGE); 49 | 50 | var app = new Gala.Daemon.Application (); 51 | return app.run (); 52 | } 53 | -------------------------------------------------------------------------------- /daemon/MonitorLabel.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 elementary, Inc. (https://elementary.io) 3 | * SPDX-License-Identifier: LGPL-3.0-or-later 4 | */ 5 | 6 | public class Gala.Daemon.MonitorLabel : Gtk.Window { 7 | private const int SPACING = 12; 8 | private const string COLORED_STYLE_CSS = """ 9 | .%s { 10 | background-color: alpha(%s, 0.8); 11 | color: %s; 12 | } 13 | """; 14 | 15 | public MonitorLabelInfo info { get; construct; } 16 | 17 | public MonitorLabel (MonitorLabelInfo info) { 18 | Object (info: info); 19 | } 20 | 21 | construct { 22 | child = new Gtk.Label (info.label); 23 | 24 | title = "LABEL-%i".printf (info.monitor); 25 | 26 | decorated = false; 27 | resizable = false; 28 | deletable = false; 29 | can_focus = false; 30 | titlebar = new Gtk.Grid (); 31 | 32 | var provider = new Gtk.CssProvider (); 33 | try { 34 | provider.load_from_string (COLORED_STYLE_CSS.printf (title, info.background_color, info.text_color)); 35 | get_style_context ().add_class (title); 36 | get_style_context ().add_class ("monitor-label"); 37 | 38 | Gtk.StyleContext.add_provider_for_display ( 39 | Gdk.Display.get_default (), 40 | provider, 41 | Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION 42 | ); 43 | } catch (Error e) { 44 | warning ("Failed to load CSS: %s", e.message); 45 | } 46 | 47 | present (); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /daemon/Window.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 elementary, Inc. (https://elementary.io) 3 | * SPDX-License-Identifier: GPL-3.0-or-later 4 | * 5 | * Authored by: Leonhard Kargl 6 | */ 7 | 8 | public class Gala.Daemon.Window : Gtk.Window { 9 | class construct { 10 | set_css_name ("daemon-window"); 11 | } 12 | 13 | construct { 14 | decorated = false; 15 | resizable = false; 16 | deletable = false; 17 | can_focus = false; 18 | title = "MODAL"; 19 | hide_on_close = true; 20 | child = new Gtk.Box (HORIZONTAL, 0) { 21 | hexpand = true, 22 | vexpand = true 23 | }; 24 | 25 | var controller = new Gtk.GestureClick (); 26 | child.add_controller (controller); 27 | controller.released.connect (close); 28 | } 29 | 30 | public override void snapshot (Gtk.Snapshot snapshot) { 31 | base.snapshot (snapshot); 32 | // We need to append something here otherwise GTK thinks the snapshot is empty and therefore doesn't 33 | // render anything and therefore doesn't present a window which is needed for our popovers 34 | snapshot.append_color ({0, 0, 0, 0}, {{0, 0}, {0, 0}}); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /daemon/meson.build: -------------------------------------------------------------------------------- 1 | gala_daemon_sources = files( 2 | 'Main.vala', 3 | 'DisplayConfig.vala', 4 | 'DBus.vala', 5 | 'MonitorLabel.vala', 6 | 'Window.vala', 7 | 'WindowMenu.vala', 8 | ) 9 | 10 | gala_daemon_bin = executable( 11 | 'gala-daemon', 12 | gala_daemon_sources, 13 | gala_resources, 14 | dependencies: [config_dep, granite_dep, gtk4_dep], 15 | include_directories: config_inc_dir, 16 | install: true, 17 | ) 18 | -------------------------------------------------------------------------------- /data/20_elementary.pantheon.wm.gschema.override: -------------------------------------------------------------------------------- 1 | [org.gnome.mutter:Pantheon] 2 | dynamic-workspaces = true 3 | attach-modal-dialogs = false 4 | edge-tiling = true 5 | 6 | [org.gnome.desktop.wm.preferences:Pantheon] 7 | button-layout='close:maximize' 8 | -------------------------------------------------------------------------------- /data/gala-daemon.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 elementary, Inc. (https://elementary.io) 3 | * SPDX-License-Identifier: GPL-3.0-or-later 4 | */ 5 | 6 | daemon-window { 7 | background: transparent; 8 | } 9 | 10 | .monitor-label { 11 | border-radius: 9px; 12 | font-weight: 600; 13 | } 14 | 15 | .monitor-label label { 16 | margin: 1em; 17 | text-shadow: 0 1px 1px alpha(white, 0.1); 18 | } 19 | -------------------------------------------------------------------------------- /data/gala-multitaskingview.desktop.in: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Type=Application 3 | Name=Multitasking View 4 | Comment=View all open windows and workspaces 5 | GenericName=Multitasking View 6 | Icon=preferences-desktop-workspaces 7 | Terminal=false 8 | Categories=GNOME;GTK;System; 9 | Exec=dbus-send --session --dest=org.pantheon.gala --print-reply /org/pantheon/gala org.pantheon.gala.PerformAction int32:1 10 | X-AppStream-Ignore=true 11 | OnlyShowIn=Pantheon; 12 | -------------------------------------------------------------------------------- /data/gala-other.desktop.in: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Type=Application 3 | Name=Other 4 | Comment=Fallback desktop file for notifications from outdated applications. 5 | Icon=applications-other 6 | NoDisplay=true 7 | X-GNOME-UsesNotifications=true 8 | -------------------------------------------------------------------------------- /data/gala-wayland.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Type=Application 3 | Name=Gala (wayland compositor) 4 | Exec=gala --wayland --display-server 5 | NoDisplay=true 6 | # name of loadable control center module 7 | X-GNOME-WMSettingsModule=metacity 8 | # name we put on the WM spec check window 9 | X-GNOME-WMName=Gala 10 | # back compat only 11 | X-GnomeWMSettingsLibrary=metacity 12 | X-GNOME-Autostart-Phase=DisplayServer 13 | X-GNOME-Autostart-Notify=true 14 | X-GNOME-HiddenUnderSystemd=true 15 | X-Ubuntu-Gettext-Domain=gala 16 | -------------------------------------------------------------------------------- /data/gala.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Type=Application 3 | Name=Gala 4 | Exec=gala 5 | NoDisplay=true 6 | # name of loadable control center module 7 | X-GNOME-WMSettingsModule=metacity 8 | # name we put on the WM spec check window 9 | X-GNOME-WMName=Gala 10 | # back compat only 11 | X-GnomeWMSettingsLibrary=metacity 12 | X-GNOME-Autostart-Phase=WindowManager 13 | X-GNOME-Provides=windowmanager 14 | X-GNOME-Autostart-Notify=true 15 | X-GNOME-HiddenUnderSystemd=true 16 | X-Ubuntu-Gettext-Domain=gala 17 | -------------------------------------------------------------------------------- /data/gala.gresource.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 20 | close.svg 21 | resize.svg 22 | 23 | 24 | shaders/colorblindness-correction.vert 25 | shaders/monochrome.vert 26 | 27 | 28 | gala-daemon.css 29 | 30 | 31 | -------------------------------------------------------------------------------- /data/gala.target: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Gala 3 | DefaultDependencies=no 4 | 5 | Requisite=gnome-session-initialized.target 6 | PartOf=gnome-session-initialized.target 7 | Before=gnome-session-initialized.target 8 | 9 | Wants=io.elementary.gala@wayland.service 10 | Wants=io.elementary.gala@x11.service 11 | -------------------------------------------------------------------------------- /data/gala@wayland.service.in: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Gala on Wayland 3 | # On wayland, force a session shutdown 4 | OnFailure=gnome-session-shutdown.target 5 | OnFailureJobMode=replace-irreversibly 6 | CollectMode=inactive-or-failed 7 | RefuseManualStart=on 8 | RefuseManualStop=on 9 | 10 | After=gnome-session-manager.target 11 | 12 | Requisite=gnome-session-initialized.target 13 | PartOf=gnome-session-initialized.target 14 | Before=gnome-session-initialized.target 15 | 16 | #NOTE: ConditionEnvironment works with systemd >= 246 17 | ConditionEnvironment=XDG_SESSION_TYPE=%I 18 | 19 | [Service] 20 | Slice=session.slice 21 | Type=notify 22 | ExecStart=@bindir@/gala 23 | 24 | # unset some environment variables that were set by the compositor and won't work now that the compositor is gone 25 | ExecStopPost=-/bin/sh -c 'test "$SERVICE_RESULT" != "exec-condition" && systemctl --user unset-environment GNOME_SETUP_DISPLAY WAYLAND_DISPLAY DISPLAY XAUTHORITY' 26 | 27 | # On wayland we cannot restart 28 | Restart=no 29 | # Kill any stubborn child processes after this long 30 | TimeoutStopSec=5 31 | 32 | # Lower down Gala's OOM score to avoid being killed by OOM-killer too early 33 | OOMScoreAdjust=-1000 34 | 35 | -------------------------------------------------------------------------------- /data/gala@x11.service.in: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Gala on X11 3 | # On X11, try to show the GNOME Session Failed screen 4 | OnFailure=gnome-session-failed.target 5 | OnFailureJobMode=replace 6 | CollectMode=inactive-or-failed 7 | RefuseManualStart=on 8 | RefuseManualStop=on 9 | 10 | After=gnome-session-manager.target 11 | 12 | Requisite=gnome-session-initialized.target 13 | PartOf=gnome-session-initialized.target 14 | Before=gnome-session-initialized.target 15 | 16 | #NOTE: ConditionEnvironment works with systemd >= 246 17 | ConditionEnvironment=XDG_SESSION_TYPE=%I 18 | 19 | # Limit startup frequency more than the default 20 | StartLimitIntervalSec=15s 21 | StartLimitBurst=3 22 | 23 | [Service] 24 | Slice=session.slice 25 | Type=notify 26 | ExecStart=@bindir@/gala 27 | 28 | # On X11 we do not need to unset any variables 29 | 30 | # On X11 we want to restart on-success (Alt+F2 + r) and on-failure. 31 | Restart=always 32 | # Do not wait before restarting the shell 33 | RestartSec=0ms 34 | # Kill any stubborn child processes after this long 35 | TimeoutStopSec=5 36 | 37 | # Lower down gnome-shell's OOM score to avoid being killed by OOM-killer too early 38 | OOMScoreAdjust=-1000 39 | 40 | 41 | -------------------------------------------------------------------------------- /data/io.elementary.desktop.wm.shell: -------------------------------------------------------------------------------- 1 | [io.elementary.wingpanel] 2 | launch-on-x=true 3 | args=io.elementary.wingpanel 4 | 5 | [io.elementary.dock] 6 | launch-on-x=true 7 | args=io.elementary.dock 8 | -------------------------------------------------------------------------------- /data/meson.build: -------------------------------------------------------------------------------- 1 | install_data( 2 | 'gala.gschema.xml', 3 | install_dir: join_paths(data_dir, 'glib-2.0', 'schemas'), 4 | rename: 'org.pantheon.desktop.gala.gschema.xml' 5 | ) 6 | 7 | install_data( 8 | 'io.elementary.desktop.wm.shell', 9 | install_dir: get_option('sysconfdir') / 'xdg', 10 | ) 11 | 12 | i18n.merge_file( 13 | input: 'gala.metainfo.xml.in', 14 | output: meson.project_name() + '.metainfo.xml', 15 | po_dir: meson.global_source_root() / 'po', 16 | type: 'xml', 17 | install: true, 18 | install_dir: get_option('datadir') / 'metainfo', 19 | ) 20 | 21 | i18n.merge_file( 22 | input: 'gala-multitaskingview.desktop.in', 23 | output: 'gala-multitaskingview.desktop', 24 | po_dir: join_paths(meson.global_source_root (), 'po'), 25 | type: 'desktop', 26 | install: true, 27 | install_dir: join_paths(data_dir, 'applications') 28 | ) 29 | 30 | i18n.merge_file( 31 | input: 'gala-other.desktop.in', 32 | output: 'gala-other.desktop', 33 | po_dir: join_paths(meson.global_source_root (), 'po'), 34 | type: 'desktop', 35 | install: true, 36 | install_dir: join_paths(data_dir, 'applications') 37 | ) 38 | install_data(['gala.desktop', 'gala-wayland.desktop'], install_dir: join_paths(data_dir, 'applications')) 39 | install_data(files('20_elementary.pantheon.wm.gschema.override'), install_dir: join_paths(data_dir, 'glib-2.0', 'schemas')) 40 | 41 | if get_option('systemd') 42 | dep_systemd = dependency('systemd', required: true) 43 | systemd_userunitdir = get_option('systemduserunitdir') 44 | if systemd_userunitdir == '' 45 | systemd_userunitdir = dep_systemd.get_variable('systemduserunitdir', pkgconfig_define: ['prefix', get_option('prefix')]) 46 | endif 47 | 48 | bindir = join_paths(get_option('prefix'), get_option('bindir')) 49 | unit_conf = configuration_data() 50 | unit_conf.set('bindir', bindir) 51 | 52 | configure_file( 53 | input: 'gala@x11.service.in', 54 | output: 'io.elementary.gala@x11.service', 55 | install: true, 56 | install_dir: systemd_userunitdir, 57 | configuration: unit_conf 58 | ) 59 | 60 | configure_file( 61 | input: 'gala@wayland.service.in', 62 | output: 'io.elementary.gala@wayland.service', 63 | install: true, 64 | install_dir: systemd_userunitdir, 65 | configuration: unit_conf 66 | ) 67 | 68 | install_data( 69 | 'gala.target', 70 | rename: 'io.elementary.gala.target', 71 | install_dir: systemd_userunitdir 72 | ) 73 | endif 74 | -------------------------------------------------------------------------------- /data/shaders/colorblindness-correction.vert: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022-2023 GdH 3 | * Copyright 2023 elementary, Inc. 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | */ 6 | 7 | 8 | uniform sampler2D tex; 9 | uniform int COLORBLIND_MODE; 10 | uniform float STRENGTH; 11 | void main() { 12 | vec4 c = texture2D(tex, cogl_tex_coord0_in.xy); 13 | 14 | // RGB to LMS matrix 15 | float L = (17.8824f * c.r) + (43.5161f * c.g) + (4.11935f * c.b); 16 | float M = (3.45565f * c.r) + (27.1554f * c.g) + (3.86714f * c.b); 17 | float S = (0.0299566f * c.r) + (0.184309f * c.g) + (1.46709f * c.b); 18 | 19 | float l, m, s; 20 | 21 | // Remove invisible colors 22 | if ( COLORBLIND_MODE == 1 || COLORBLIND_MODE == 2) { // Protanopia - reds are greatly reduced 23 | l = 0.0f * L + 2.02344f * M + -2.52581f * S; 24 | m = 0.0f * L + 1.0f * M + 0.0f * S; 25 | s = 0.0f * L + 0.0f * M + 1.0f * S; 26 | } else if ( COLORBLIND_MODE == 3 || COLORBLIND_MODE == 4) { // Deuteranopia - greens are greatly reduced 27 | l = 1.0f * L + 0.0f * M + 0.0f * S; 28 | m = 0.494207f * L + 0.0f * M + 1.24827f * S; 29 | s = 0.0f * L + 0.0f * M + 1.0f * S; 30 | } else if ( COLORBLIND_MODE == 5 ) { // Tritanopia - blues are greatly reduced (1 of 10 000) 31 | l = 1.0f * L + 0.0f * M + 0.0f * S; 32 | m = 0.0f * L + 1.0f * M + 0.0f * S; 33 | // GdH - trinatopia vector calculated by me, all public sources were off 34 | s = -0.012491378299329402f * L + 0.07203451899279534f * M + 0.0f * S; 35 | } 36 | 37 | // LMS to RGB matrix conversion 38 | vec4 error; 39 | error.r = (0.0809444479f * l) + (-0.130504409f * m) + (0.116721066f * s); 40 | error.g = (-0.0102485335f * l) + (0.0540193266f * m) + (-0.113614708f * s); 41 | error.b = (-0.000365296938f * l) + (-0.00412161469f * m) + (0.693511405f * s); 42 | // The error is what they see 43 | 44 | // ratio between original and error colors allows adjusting filter for weaker forms of dichromacy 45 | error = error * STRENGTH + c * (1.0 - STRENGTH); 46 | error.a = 1.0; 47 | 48 | // Isolate invisible colors to color vision deficiency (calculate error matrix) 49 | error = (c - error); 50 | 51 | // Shift colors 52 | vec4 correction; 53 | // protanopia / protanomaly corrections 54 | if ( COLORBLIND_MODE == 1 ) { 55 | //(kwin effect values) 56 | correction.r = error.r * 0.56667 + error.g * 0.43333 + error.b * 0.00000; 57 | correction.g = error.r * 0.55833 + error.g * 0.44267 + error.b * 0.00000; 58 | correction.b = error.r * 0.00000 + error.g * 0.24167 + error.b * 0.75833; 59 | // tries to mimic Android, GdH 60 | //correction.r = error.r * -0.5 + error.g * -0.3 + error.b * 0.0; 61 | //correction.g = error.r * 0.2 + error.g * 0.0 + error.b * 0.0; 62 | //correction.b = error.r * 0.2 + error.g * 1.0 + error.b * 1.0; 63 | // protanopia / protanomaly high contrast G-R corrections 64 | } else if ( COLORBLIND_MODE == 2 ) { 65 | correction.r = error.r * 2.56667 + error.g * 0.43333 + error.b * 0.00000; 66 | correction.g = error.r * 1.55833 + error.g * 0.44267 + error.b * 0.00000; 67 | correction.b = error.r * 0.00000 + error.g * 0.24167 + error.b * 0.75833; 68 | // deuteranopia / deuteranomaly corrections (tries to mimic Android, GdH) 69 | } else if ( COLORBLIND_MODE == 3 ) { 70 | correction.r = error.r * -0.7 + error.g * 0.0 + error.b * 0.0; 71 | correction.g = error.r * 0.5 + error.g * 1.0 + error.b * 0.0; 72 | correction.b = error.r * -0.3 + error.g * 0.0 + error.b * 1.0; 73 | // deuteranopia / deuteranomaly high contrast R-G corrections 74 | } else if ( COLORBLIND_MODE == 4 ) { 75 | correction.r = error.r * -1.5 + error.g * 1.5 + error.b * 0.0; 76 | correction.g = error.r * -1.5 + error.g * 1.5 + error.b * 0.0; 77 | correction.b = error.r * 1.5 + error.g * 0.0 + error.b * 0.0; 78 | // tritanopia / tritanomaly corrections (GdH) 79 | } else if ( COLORBLIND_MODE == 5 ) { 80 | correction.r = error.r * 0.3 + error.g * 0.5 + error.b * 0.4; 81 | correction.g = error.r * 0.5 + error.g * 0.7 + error.b * 0.3; 82 | correction.b = error.r * 0.0 + error.g * 0.0 + error.b * 1.0; 83 | } 84 | 85 | // Add compensation to original values 86 | correction = c + correction; 87 | correction.a = c.a; 88 | 89 | cogl_color_out = correction; 90 | } 91 | -------------------------------------------------------------------------------- /data/shaders/monochrome.vert: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 elementary, Inc. 3 | * SPDX-License-Identifier: GPL-3.0-or-later 4 | */ 5 | 6 | uniform sampler2D tex; 7 | uniform float STRENGTH; 8 | void main() { 9 | vec2 uv = cogl_tex_coord0_in.xy; 10 | vec4 sample = texture2D (tex, uv); 11 | vec3 luminance = vec3 (0.2126, 0.7512, 0.0722); 12 | float gray = luminance.r * sample.r + luminance.g * sample.g + luminance.b * sample.b; 13 | cogl_color_out = vec4 ( 14 | sample.r * (1.0 - STRENGTH) + gray * STRENGTH, 15 | sample.g * (1.0 - STRENGTH) + gray * STRENGTH, 16 | sample.b * (1.0 - STRENGTH) + gray * STRENGTH, 17 | sample.a 18 | ) ; 19 | } 20 | -------------------------------------------------------------------------------- /docs/meson.build: -------------------------------------------------------------------------------- 1 | valadoc = find_program('valadoc') 2 | 3 | mutter_packages_command = [] 4 | foreach dep : mutter_dep 5 | mutter_packages_command += [ '--pkg', dep.name() ] 6 | endforeach 7 | 8 | basic_command = [ 9 | valadoc, 10 | '--force', 11 | '--verbose', 12 | '--package-name','gala', 13 | '--package-version', '0.0.0', 14 | '--driver', vala.version(), 15 | mutter_packages_command, 16 | '--pkg', 'atk-bridge-2.0', 17 | '--pkg', 'gnome-desktop-3.0', 18 | '--pkg', 'gtk+-3.0', 19 | '--pkg', 'gee-0.8', 20 | '--pkg', 'gio-unix-2.0', 21 | '--pkg', 'gmodule-2.0', 22 | '--pkg', 'posix', 23 | '--pkg', 'libcanberra', 24 | '--pkg', 'sqlite3', 25 | '--pkg', 'libsystemd', 26 | '--pkg', 'granite', 27 | '--pkg', 'config', 28 | vala_flags, 29 | '--vapidir=' + join_paths(meson.build_root(), 'lib'), 30 | '--vapidir=' + join_paths(meson.global_source_root(), 'vapi'), 31 | '--doclet=html', 32 | '--use-svg-images' 33 | ] 34 | 35 | doc_target = custom_target( 36 | 'library documentation', 37 | command: [ 38 | basic_command, 39 | '-o', '@OUTPUT@', 40 | '@INPUT@' 41 | ], 42 | build_by_default: true, 43 | input: gala_lib_sources, 44 | output: 'library' 45 | ) 46 | 47 | all_doc_target = custom_target( 48 | 'full documentation', 49 | command: [ 50 | basic_command, 51 | '--internal', 52 | '--pkg', 'granite', 53 | '--pkg', 'gnome-desktop-3.0', 54 | '--pkg', 'gmodule-2.0', 55 | '--pkg', 'wayland-server', 56 | '--pkg', 'pantheon-desktop-shell', 57 | '--vapidir=' + join_paths(meson.global_source_root(), 'protocol'), 58 | '-o', '@OUTPUT@', 59 | '@INPUT@' 60 | ], 61 | build_by_default: true, 62 | input: gala_lib_sources + gala_bin_sources, 63 | output: 'full' 64 | ) 65 | -------------------------------------------------------------------------------- /lib/ActivatableComponent.vala: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2014 Tom Beckmann 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program 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 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | // 17 | 18 | namespace Gala { 19 | /** 20 | * Implement this interface on your {@link Plugin} class if you want to 21 | * replace a component like the window overview or the multitasking view. 22 | * It allows gala to hook up functionality like hotcorners and dbus 23 | * invocation of your component. 24 | */ 25 | public interface ActivatableComponent : Object { 26 | /** 27 | * The component was requested to be opened. 28 | * 29 | * @param hints The hashmap may contain special parameters that are useful 30 | * to the component. 31 | */ 32 | public abstract void open (HashTable? hints = null); 33 | 34 | /** 35 | * The component was requested to be closed. 36 | * 37 | * @param hints The hashmap may contain special parameters that are useful 38 | * to the component. 39 | */ 40 | public abstract void close (HashTable? hints = null); 41 | 42 | /** 43 | * Should return whether the component is currently opened. Used mainly for 44 | * toggling by the window manager. 45 | * 46 | * @return Return true if the component is opened. 47 | */ 48 | public abstract bool is_opened (); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /lib/AppCache.vala: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2020 elementary, Inc. (https://elementary.io) 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program 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 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | // 17 | 18 | public class Gala.AppCache : GLib.Object { 19 | public signal void changed (); 20 | 21 | private const int DEFAULT_TIMEOUT_SECONDS = 3; 22 | 23 | private GLib.HashTable startup_wm_class_to_id; 24 | private GLib.HashTable id_to_app; 25 | 26 | private GLib.AppInfoMonitor app_info_monitor; 27 | 28 | private uint queued_update_id = 0; 29 | 30 | construct { 31 | startup_wm_class_to_id = new GLib.HashTable (str_hash, str_equal); 32 | id_to_app = new GLib.HashTable (str_hash, str_equal); 33 | 34 | app_info_monitor = GLib.AppInfoMonitor.@get (); 35 | app_info_monitor.changed.connect (queue_cache_update); 36 | 37 | rebuild_cache.begin (); 38 | } 39 | 40 | private void queue_cache_update () { 41 | if (queued_update_id != 0) { 42 | GLib.Source.remove (queued_update_id); 43 | } 44 | 45 | queued_update_id = GLib.Timeout.add_seconds (DEFAULT_TIMEOUT_SECONDS, () => { 46 | rebuild_cache.begin ((obj, res) => { 47 | rebuild_cache.end (res); 48 | changed (); 49 | 50 | queued_update_id = 0; 51 | }); 52 | 53 | return GLib.Source.REMOVE; 54 | }); 55 | } 56 | 57 | private async void rebuild_cache () { 58 | SourceFunc callback = rebuild_cache.callback; 59 | 60 | new Thread ("rebuild_cache", () => { 61 | lock (startup_wm_class_to_id) { 62 | startup_wm_class_to_id.remove_all (); 63 | id_to_app.remove_all (); 64 | 65 | var app_infos = GLib.AppInfo.get_all (); 66 | 67 | foreach (unowned GLib.AppInfo app in app_infos) { 68 | unowned string id = app.get_id (); 69 | unowned string? startup_wm_class = ((GLib.DesktopAppInfo)app).get_startup_wm_class (); 70 | 71 | id_to_app[id] = (GLib.DesktopAppInfo)app; 72 | 73 | if (startup_wm_class == null) { 74 | continue; 75 | } 76 | 77 | unowned var old_id = startup_wm_class_to_id[startup_wm_class]; 78 | if (old_id == null || id == startup_wm_class) { 79 | startup_wm_class_to_id[startup_wm_class] = id; 80 | } 81 | } 82 | } 83 | 84 | Idle.add ((owned)callback); 85 | }); 86 | 87 | yield; 88 | } 89 | 90 | public unowned GLib.DesktopAppInfo? lookup_id (string? id) { 91 | if (id == null) { 92 | return null; 93 | } 94 | 95 | return id_to_app[id]; 96 | } 97 | 98 | public GLib.DesktopAppInfo? lookup_startup_wmclass (string? wm_class) { 99 | if (wm_class == null) { 100 | return null; 101 | } 102 | 103 | unowned var id = startup_wm_class_to_id[wm_class]; 104 | if (id == null) { 105 | return null; 106 | } 107 | 108 | return id_to_app[id]; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /lib/AppSystem.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 elementary, Inc. 3 | * Copyright 2021 Corentin Noël 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | */ 6 | 7 | public class Gala.AppSystem : GLib.Object { 8 | private static GLib.Once instance; 9 | public static unowned AppSystem get_default () { 10 | return instance.once (() => new AppSystem ()); 11 | } 12 | 13 | private GLib.HashTable running_apps; 14 | private GLib.HashTable id_to_app; 15 | private GLib.HashTable startup_wm_class_to_id; 16 | private Gala.AppCache app_cache; 17 | 18 | construct { 19 | id_to_app = new GLib.HashTable (str_hash, str_equal); 20 | startup_wm_class_to_id = new GLib.HashTable (str_hash, str_equal); 21 | running_apps = new GLib.HashTable (null, null); 22 | app_cache = new AppCache (); 23 | } 24 | 25 | public unowned Gala.App? lookup_app (string id) { 26 | unowned Gala.App? app = id_to_app.lookup (id); 27 | if (app != null) { 28 | return app; 29 | } 30 | 31 | GLib.DesktopAppInfo? info = app_cache.lookup_id (id); 32 | if (info == null) { 33 | return null; 34 | } 35 | 36 | var owned_app = new Gala.App (info); 37 | app = owned_app; 38 | id_to_app.insert (owned_app.id, (owned) owned_app); 39 | return app; 40 | } 41 | 42 | public unowned Gala.App? lookup_startup_wmclass (string? wmclass) { 43 | if (wmclass == null) { 44 | return null; 45 | } 46 | 47 | GLib.DesktopAppInfo? info = app_cache.lookup_startup_wmclass (wmclass); 48 | if (info == null) { 49 | return null; 50 | } 51 | 52 | return lookup_app (info.get_id ()); 53 | } 54 | 55 | private unowned Gala.App? lookup_heuristic_basename (string name) { 56 | /* Vendor prefixes are something that can be preprended to a .desktop 57 | * file name. 58 | */ 59 | const string[] VENDOR_PREFIXES = { 60 | "gnome-", 61 | "fedora-", 62 | "mozilla-", 63 | "debian-", 64 | }; 65 | 66 | unowned Gala.App? result = lookup_app (name); 67 | if (result != null) { 68 | return result; 69 | } 70 | 71 | foreach (unowned string prefix in VENDOR_PREFIXES) { 72 | result = lookup_app (prefix.concat (name)); 73 | if (result != null) { 74 | return result; 75 | } 76 | } 77 | 78 | return null; 79 | } 80 | 81 | public unowned Gala.App? lookup_desktop_wmclass (string? wmclass) { 82 | if (wmclass == null) { 83 | return null; 84 | } 85 | 86 | /* First try without changing the case (this handles 87 | org.example.Foo.Bar.desktop applications) 88 | 89 | Note that is slightly wrong in that Gtk+ would set 90 | the WM_CLASS to Org.example.Foo.Bar, but it also 91 | sets the instance part to org.example.Foo.Bar, so we're ok 92 | */ 93 | var desktop_file = wmclass.concat (".desktop"); 94 | unowned Gala.App? app = lookup_heuristic_basename (desktop_file); 95 | if (app != null) { 96 | return app; 97 | } 98 | 99 | /* This handles "Fedora Eclipse", probably others. 100 | * Note _strdelimit is modify-in-place. */ 101 | desktop_file._delimit (" ", '-'); 102 | 103 | desktop_file = desktop_file.ascii_down ().concat (".desktop"); 104 | 105 | return lookup_heuristic_basename (desktop_file); 106 | } 107 | 108 | public void notify_app_state_changed (Gala.App app) { 109 | if (app.state == Gala.AppState.RUNNING) { 110 | running_apps.insert (app, app); 111 | } else if (app.state == Gala.AppState.STOPPED) { 112 | running_apps.remove (app); 113 | } 114 | } 115 | 116 | public GLib.List get_running_apps () { 117 | return running_apps.get_keys (); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /lib/BackgroundManager.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2024 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | public interface Gala.BackgroundManagerInterface : Meta.BackgroundGroup { 7 | public abstract Meta.BackgroundActor newest_background_actor { get; } 8 | } 9 | -------------------------------------------------------------------------------- /lib/CanvasActor.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 elementary, Inc. (https://elementary.io) 3 | * SPDX-License-Identifier: LGPL-2.0-or-later 4 | */ 5 | 6 | public class Gala.CanvasActor : Clutter.Actor { 7 | private Gala.Drawing.Canvas canvas; 8 | 9 | construct { 10 | canvas = new Gala.Drawing.Canvas (); 11 | content = canvas; 12 | canvas.draw.connect ((ctx, width, height) => { 13 | draw (ctx, width, height); 14 | }); 15 | } 16 | 17 | public override void resource_scale_changed () { 18 | canvas.set_scale_factor (get_resource_scale ()); 19 | } 20 | 21 | public override void allocate (Clutter.ActorBox box) { 22 | base.allocate (box); 23 | canvas.set_size ((int)box.get_width (), (int)box.get_height ()); 24 | canvas.set_scale_factor (get_resource_scale ()); 25 | } 26 | 27 | protected virtual void draw (Cairo.Context canvas, int width, int height) { } 28 | } 29 | -------------------------------------------------------------------------------- /lib/CloseButton.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 elementary, Inc. (https://elementary.io) 3 | * SPDX-License-Identifier: GPL-3.0-or-later 4 | */ 5 | 6 | public class Gala.CloseButton : Clutter.Actor { 7 | private const uint ANIMATION_DURATION = 100; 8 | private static Gee.HashMap close_pixbufs; 9 | 10 | public signal void triggered (uint32 timestamp); 11 | public float scale { get; construct set; } 12 | 13 | // used to avoid changing hitbox of the button 14 | private Clutter.Actor pixbuf_actor; 15 | private bool is_pressed = false; 16 | 17 | public CloseButton (float scale) { 18 | Object (scale: scale); 19 | } 20 | 21 | static construct { 22 | close_pixbufs = new Gee.HashMap (); 23 | } 24 | 25 | construct { 26 | reactive = true; 27 | 28 | pixbuf_actor = new Clutter.Actor () { 29 | pivot_point = { 0.5f, 0.5f } 30 | }; 31 | add_child (pixbuf_actor); 32 | 33 | var pixbuf = get_close_button_pixbuf (scale); 34 | if (pixbuf != null) { 35 | try { 36 | var image = new Clutter.Image (); 37 | Cogl.PixelFormat pixel_format = (pixbuf.get_has_alpha () ? Cogl.PixelFormat.RGBA_8888 : Cogl.PixelFormat.RGB_888); 38 | image.set_data (pixbuf.get_pixels (), pixel_format, pixbuf.width, pixbuf.height, pixbuf.rowstride); 39 | 40 | pixbuf_actor.set_content (image); 41 | pixbuf_actor.set_size (pixbuf.width, pixbuf.height); 42 | set_size (pixbuf.width, pixbuf.height); 43 | } catch (Error e) { 44 | create_error_texture (); 45 | } 46 | } else { 47 | create_error_texture (); 48 | } 49 | } 50 | 51 | private static Gdk.Pixbuf? get_close_button_pixbuf (float scale) { 52 | var height = Utils.scale_to_int (36, scale); 53 | 54 | if (close_pixbufs[height] == null) { 55 | try { 56 | close_pixbufs[height] = new Gdk.Pixbuf.from_resource_at_scale ( 57 | Config.RESOURCEPATH + "/buttons/close.svg", 58 | -1, 59 | height, 60 | true 61 | ); 62 | } catch (Error e) { 63 | critical (e.message); 64 | return null; 65 | } 66 | } 67 | 68 | return close_pixbufs[height]; 69 | } 70 | 71 | private void create_error_texture () { 72 | // we'll just make this red so there's at least something as an 73 | // indicator that loading failed. Should never happen and this 74 | // works as good as some weird fallback-image-failed-to-load pixbuf 75 | critical ("Could not create close button"); 76 | 77 | var size = Utils.scale_to_int (36, scale); 78 | pixbuf_actor.set_size (size, size); 79 | pixbuf_actor.background_color = { 255, 0, 0, 255 }; 80 | } 81 | 82 | public override bool button_press_event (Clutter.Event e) { 83 | var estimated_duration = (uint) (ANIMATION_DURATION * (scale_x - 0.8) / 0.2); 84 | 85 | pixbuf_actor.save_easing_state (); 86 | pixbuf_actor.set_easing_duration (estimated_duration); 87 | pixbuf_actor.set_easing_mode (Clutter.AnimationMode.EASE_IN_OUT); 88 | pixbuf_actor.set_scale (0.8, 0.8); 89 | pixbuf_actor.restore_easing_state (); 90 | 91 | is_pressed = true; 92 | 93 | return Clutter.EVENT_STOP; 94 | } 95 | 96 | public override bool button_release_event (Clutter.Event e) { 97 | reset_scale (); 98 | 99 | if (is_pressed) { 100 | triggered (e.get_time ()); 101 | is_pressed = false; 102 | } 103 | 104 | return Clutter.EVENT_STOP; 105 | } 106 | 107 | public override bool leave_event (Clutter.Event event) { 108 | reset_scale (); 109 | is_pressed = false; 110 | 111 | return Clutter.EVENT_PROPAGATE; 112 | } 113 | 114 | private void reset_scale () { 115 | var estimated_duration = (uint) (ANIMATION_DURATION * (1.0 - scale_x) / 0.2); 116 | 117 | pixbuf_actor.save_easing_state (); 118 | pixbuf_actor.set_easing_duration (estimated_duration); 119 | pixbuf_actor.set_easing_mode (Clutter.AnimationMode.EASE_IN_OUT); 120 | pixbuf_actor.set_scale (1.0, 1.0); 121 | pixbuf_actor.restore_easing_state (); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /lib/Constants.vala: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2019 elementary, Inc. (https://elementary.io) 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program 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 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | // 17 | 18 | namespace Gala { 19 | [CCode (has_type_id = false)] 20 | public enum AnimationDuration { 21 | // Duration of the open animation 22 | OPEN = 350, 23 | // Duration of the close animation 24 | CLOSE = 195, 25 | // Duration of the hide animation 26 | HIDE = 200, 27 | // Duration of the menu mapping animation 28 | MENU_MAP = 150, 29 | // Duration of the snap animation as used by maximize/unmaximize 30 | SNAP = 250, 31 | // Duration of the workspace switch animation 32 | WORKSPACE_SWITCH_MIN = 300, 33 | WORKSPACE_SWITCH = 400, 34 | // Duration of the nudge animation when trying to switch to at the end of the workspace list 35 | NUDGE = 360, 36 | } 37 | 38 | public enum GestureAction { 39 | NONE, 40 | SWITCH_WORKSPACE, 41 | SWITCH_WINDOWS, 42 | MULTITASKING_VIEW, 43 | DOCK, 44 | ZOOM, 45 | CLOSE_WINDOW, 46 | N_ACTIONS 47 | } 48 | 49 | /** 50 | * Used as a key for Object.set_data on Meta.Windows that should be 51 | * treated as notifications. Has to be set before the window is mapped. 52 | */ 53 | public const string NOTIFICATION_DATA_KEY = "elementary-notification"; 54 | } 55 | -------------------------------------------------------------------------------- /lib/Drawing/StyleManager.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 elementary, Inc. (https://elementary.io) 3 | * SPDX-License-Identifier: GPL-3.0-or-later 4 | * 5 | * Authored by: Leonhard Kargl 6 | */ 7 | 8 | public class Gala.Drawing.StyleManager : Object { 9 | public enum ColorScheme { 10 | NO_PREFERENCE, 11 | DARK, 12 | LIGHT 13 | } 14 | 15 | [DBus (name="org.freedesktop.Accounts")] 16 | private interface Accounts : Object { 17 | public abstract async string find_user_by_name (string name) throws IOError, DBusError; 18 | } 19 | 20 | [DBus (name="io.elementary.pantheon.AccountsService")] 21 | private interface AccountsService : DBusProxy { 22 | public abstract int prefers_color_scheme { get; set; } 23 | public abstract int prefers_accent_color { get; set; } 24 | } 25 | 26 | private const string FDO_ACCOUNTS_NAME = "org.freedesktop.Accounts"; 27 | private const string FDO_ACCOUNTS_PATH = "/org/freedesktop/Accounts"; 28 | 29 | private const double ACCENT_COLOR_ALPHA = 0.25; 30 | private const Gdk.RGBA DEFAULT_ACCENT_COLOR = { 0, 0, 0, ACCENT_COLOR_ALPHA }; 31 | 32 | private static GLib.Once instance; 33 | public static StyleManager get_instance () { 34 | return instance.once (() => {return new StyleManager ();}); 35 | } 36 | 37 | public ColorScheme prefers_color_scheme { get; private set; default = LIGHT; } 38 | public Gdk.RGBA theme_accent_color { get; private set; default = DEFAULT_ACCENT_COLOR; } 39 | 40 | private AccountsService? accounts_service_proxy; 41 | 42 | construct { 43 | Bus.watch_name (SYSTEM, FDO_ACCOUNTS_NAME, NONE, () => connect_to_accounts_service.begin (), () => accounts_service_proxy = null); 44 | } 45 | 46 | private async void connect_to_accounts_service () { 47 | try { 48 | var accounts = yield Bus.get_proxy (SYSTEM, FDO_ACCOUNTS_NAME, FDO_ACCOUNTS_PATH); 49 | 50 | var path = yield accounts.find_user_by_name (Environment.get_user_name ()); 51 | 52 | accounts_service_proxy = yield Bus.get_proxy (SYSTEM, FDO_ACCOUNTS_NAME, path, GET_INVALIDATED_PROPERTIES); 53 | } catch { 54 | warning ("Could not connect to AccountsService. Default accent color will be used"); 55 | return; 56 | } 57 | 58 | update_color_scheme (accounts_service_proxy.prefers_color_scheme); 59 | update_color (accounts_service_proxy.prefers_accent_color); 60 | 61 | accounts_service_proxy.g_properties_changed.connect ((changed, invalid) => { 62 | var value = changed.lookup_value ("PrefersAccentColor", new VariantType ("i")); 63 | if (value != null) { 64 | update_color (value.get_int32 ()); 65 | } 66 | 67 | value = changed.lookup_value ("PrefersColorScheme", new VariantType ("i")); 68 | if (value != null) { 69 | update_color_scheme (value.get_int32 ()); 70 | } 71 | }); 72 | } 73 | 74 | private void update_color_scheme (int color_scheme) { 75 | prefers_color_scheme = (ColorScheme) color_scheme; 76 | } 77 | 78 | private void update_color (int color) { 79 | var rgb = get_color (color); 80 | 81 | double r = ((rgb >> 16) & 255) / 255.0; 82 | double g = ((rgb >> 8) & 255) / 255.0; 83 | double b = (rgb & 255) / 255.0; 84 | 85 | theme_accent_color = { 86 | r, 87 | g, 88 | b, 89 | ACCENT_COLOR_ALPHA 90 | }; 91 | } 92 | 93 | private int get_color (int color) { 94 | switch (color) { 95 | case 1: // Strawberry 96 | return 0xed5353; 97 | 98 | case 2: // Orange 99 | return 0xffa154; 100 | 101 | case 3: // Banana 102 | return 0xf9c440; 103 | 104 | case 4: // Lime 105 | return 0x68b723; 106 | 107 | case 5: // Mint 108 | return 0x28bca3; 109 | 110 | case 6: // Blueberry 111 | return 0x3689e6; 112 | 113 | case 7: // Grape 114 | return 0xa56de2; 115 | 116 | case 8: // Bubblegum 117 | return 0xde3e80; 118 | 119 | case 9: // Cocoa 120 | return 0x8a715e; 121 | 122 | case 10: // Slate 123 | return 0x667885; 124 | } 125 | 126 | return 0; 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /lib/Drawing/Utilities.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 elementary, Inc. (https://elementary.io) 3 | * Copyright 2011-2013 Maxwell Barvian 4 | * Copyright Robert Dyer 5 | * SPDX-License-Identifier: LGPL-3.0-or-later 6 | */ 7 | 8 | /** 9 | * A utility class for frequently-performed drawing operations. 10 | */ 11 | public class Gala.Drawing.Utilities : GLib.Object { 12 | 13 | /** 14 | * Adds a closed sub-path rounded rectangle of the given size and border radius to the current path 15 | * at position (x, y) in user-space coordinates. 16 | * 17 | * @param cr a {@link Cairo.Context} 18 | * @param x the X coordinate of the top left corner of the rounded rectangle 19 | * @param y the Y coordinate to the top left corner of the rounded rectangle 20 | * @param width the width of the rounded rectangle 21 | * @param height the height of the rounded rectangle 22 | * @param radius the border radius of the rounded rectangle 23 | */ 24 | public static void cairo_rounded_rectangle ( 25 | Cairo.Context cr, 26 | double x, 27 | double y, 28 | double width, 29 | double height, 30 | double radius 31 | ) { 32 | cr.move_to (x + radius, y); 33 | cr.arc (x + width - radius, y + radius, radius, Math.PI * 1.5, Math.PI * 2); 34 | cr.arc (x + width - radius, y + height - radius, radius, 0, Math.PI * 0.5); 35 | cr.arc (x + radius, y + height - radius, radius, Math.PI * 0.5, Math.PI); 36 | cr.arc (x + radius, y + radius, radius, Math.PI, Math.PI * 1.5); 37 | cr.close_path (); 38 | } 39 | 40 | /** 41 | * Averages the colors in the {@link Gdk.Pixbuf} and returns it. 42 | * 43 | * @param source the {@link Gdk.Pixbuf} 44 | * 45 | * @return the {@link Gala.Drawing.Color} containing the averaged color 46 | */ 47 | public static Drawing.Color average_color (Gdk.Pixbuf source) { 48 | var r_total = 0.0; 49 | var g_total = 0.0; 50 | var b_total = 0.0; 51 | 52 | uint8* data_ptr = source.get_pixels (); 53 | double pixels = source.height * source.rowstride / source.n_channels; 54 | 55 | for (var i = 0; i < pixels; i++) { 56 | var r = data_ptr [0]; 57 | var g = data_ptr [1]; 58 | var b = data_ptr [2]; 59 | 60 | var max = (uint8) double.max (r, double.max (g, b)); 61 | var min = (uint8) double.min (r, double.min (g, b)); 62 | double delta = max - min; 63 | 64 | var sat = delta == 0 ? 0.0 : delta / max; 65 | var score = 0.2 + 0.8 * sat; 66 | 67 | r_total += r * score; 68 | g_total += g * score; 69 | b_total += b * score; 70 | 71 | data_ptr += source.n_channels; 72 | } 73 | 74 | return new Drawing.Color ( 75 | r_total / uint8.MAX / pixels, 76 | g_total / uint8.MAX / pixels, 77 | b_total / uint8.MAX / pixels, 78 | 1 79 | ).set_val (0.8).multiply_sat (1.15); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /lib/WindowIcon.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Tom Beckmann 3 | * Copyright 2012 Rico Tzschichholz 4 | * Copyright 2023 elementary, Inc. 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | /** 9 | * Creates a new ClutterTexture with an icon for the window at the given size. 10 | * This is recommended way to grab an icon for a window as this method will make 11 | * sure the icon is updated if it becomes available at a later point. 12 | */ 13 | public class Gala.WindowIcon : Clutter.Actor { 14 | public Meta.Window window { get; construct; } 15 | public int icon_size { get; construct; } 16 | public int scale { get; construct; } 17 | 18 | /** 19 | * Creates a new WindowIcon 20 | * 21 | * @param window The window for which to create the icon 22 | * @param icon_size The size of the icon in pixels 23 | * @param scale The desired scale of the icon 24 | */ 25 | public WindowIcon (Meta.Window window, int icon_size, int scale = 1) { 26 | Object (window: window, 27 | icon_size: icon_size, 28 | scale: scale); 29 | } 30 | 31 | construct { 32 | /** 33 | * Sometimes a WindowIcon is constructed on Meta.Display::window_created. 34 | * In this case it can happen that we don't have any info about the app yet so we can't get the 35 | * correct icon. Therefore we check whether the info becomes available at some point 36 | * and if it does we try to get a new icon. 37 | */ 38 | window.notify["wm-class"].connect (reload_icon); 39 | window.notify["gtk-application-id"].connect (reload_icon); 40 | 41 | reload_icon (); 42 | } 43 | 44 | private void reload_icon () { 45 | width = icon_size * scale; 46 | height = icon_size * scale; 47 | 48 | var pixbuf = Gala.Utils.get_icon_for_window (window, icon_size, scale); 49 | try { 50 | var image = new Clutter.Image (); 51 | Cogl.PixelFormat pixel_format = (pixbuf.get_has_alpha () ? Cogl.PixelFormat.RGBA_8888 : Cogl.PixelFormat.RGB_888); 52 | image.set_data (pixbuf.get_pixels (), pixel_format, pixbuf.width, pixbuf.height, pixbuf.rowstride); 53 | set_content (image); 54 | } catch (Error e) {} 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /lib/gala.deps.in: -------------------------------------------------------------------------------- 1 | gdk-pixbuf-2.0 2 | glib-2.0 3 | gobject-2.0 4 | posix 5 | @MUTTER_DEP@ 6 | -------------------------------------------------------------------------------- /lib/meson.build: -------------------------------------------------------------------------------- 1 | gala_lib_sources = files( 2 | 'ActivatableComponent.vala', 3 | 'App.vala', 4 | 'AppCache.vala', 5 | 'AppSystem.vala', 6 | 'BackgroundManager.vala', 7 | 'CanvasActor.vala', 8 | 'CloseButton.vala', 9 | 'Constants.vala', 10 | 'DragDropAction.vala', 11 | 'Drawing/BufferSurface.vala', 12 | 'Drawing/Canvas.vala', 13 | 'Drawing/Color.vala', 14 | 'Drawing/StyleManager.vala', 15 | 'Drawing/Utilities.vala', 16 | 'Plugin.vala', 17 | 'ShadowEffect.vala', 18 | 'Utils.vala', 19 | 'WindowIcon.vala', 20 | 'WindowManager.vala', 21 | ) 22 | 23 | gala_resources = gnome.compile_resources( 24 | 'gala-resources', 25 | join_paths(meson.global_source_root(), 'data', 'gala.gresource.xml'), 26 | source_dir: join_paths(meson.global_source_root(), 'data'), 27 | c_name: 'gala', 28 | ) 29 | 30 | gala_lib = shared_library( 31 | 'gala', 32 | gala_lib_sources, 33 | gala_resources, 34 | dependencies: [gala_base_dep], 35 | include_directories: config_inc_dir, 36 | install: true, 37 | install_dir: [true, join_paths(get_option('includedir'), 'gala'), true], 38 | install_rpath: mutter_typelib_dir, 39 | version : '0.0.0' 40 | ) 41 | 42 | deps_conf = configuration_data() 43 | deps_conf.set('MUTTER_DEP', libmutter_dep.name()) 44 | config_h = configure_file( 45 | input: 'gala.deps.in', 46 | output: '@BASENAME@', 47 | configuration: deps_conf, 48 | install_dir: join_paths(get_option('datadir'), 'vala', 'vapi') 49 | ) 50 | 51 | gala_dep = declare_dependency(link_with: [gala_lib], include_directories: include_directories('.')) 52 | 53 | pkg.generate( 54 | gala_lib, 55 | filebase: 'gala', 56 | name: 'Gala', 57 | description: 'Library to develop plugins for Gala', 58 | subdirs: 'gala', 59 | requires: [glib_dep, gobject_dep, gio_dep, gio_unix_dep, libmutter_dep], 60 | variables: [ 61 | 'datarootdir=${prefix}/@0@'.format(get_option('datadir')), 62 | 'pkgdatadir=${datarootdir}/gala' 63 | ] 64 | ) 65 | -------------------------------------------------------------------------------- /meson_options.txt: -------------------------------------------------------------------------------- 1 | option ('documentation', type : 'boolean', value : false) 2 | option ('systemd', type : 'boolean', value : true) 3 | option ('systemduserunitdir', type : 'string', value : '') 4 | -------------------------------------------------------------------------------- /plugins/pip/meson.build: -------------------------------------------------------------------------------- 1 | gala_pip_sources = [ 2 | 'Main.vala', 3 | 'PopupWindow.vala', 4 | 'SelectionArea.vala' 5 | ] 6 | 7 | gala_pip_lib = shared_library( 8 | 'gala-pip', 9 | gala_pip_sources, 10 | dependencies: [gala_dep, gala_base_dep], 11 | include_directories: config_inc_dir, 12 | install: true, 13 | install_dir: plugins_dir, 14 | install_rpath: mutter_typelib_dir, 15 | ) 16 | -------------------------------------------------------------------------------- /plugins/template/README: -------------------------------------------------------------------------------- 1 | 2 | Note for compilition 3 | -------------------- 4 | If you want your own plugin within this source tree 5 | don't forget to add the new subdirectory to the plugins' Makefile.am 6 | SUBDIRS list and add your Makefile to the list of Makefiles found at 7 | about the end of the configure.ac file AC_CONFIG_FILES. 8 | The API is currently internal until the API is finalized, so you have 9 | to build it in this source tree. 10 | 11 | Some more useful notes on developing plugins: 12 | 13 | Modal Mode 14 | ---------- 15 | If you want to display large elements that can be toggled instead of small overlays, 16 | you can use wm.begin_modal() to make Gala enter modal mode. In this mode, you'll be 17 | able to receive key events and all mouse events will be delivered regardless of the 18 | region you have set. Don't forget to call wm.end_modal() and provide an obvious way 19 | to exit modal mode for the user, otherwise he will be stuck and can only restart 20 | Gala. 21 | 22 | Keybindings 23 | ----------- 24 | To add keybindings, you'll need a gsettings schema. You can take a look at Gala's 25 | schema in data/org.pantheon.desktop.gschema.xml for an example. You'll also find 26 | how to correctly declare shortcut keys in that file. Once you got this file ready 27 | it's pretty easy. Just enable its installation in cmake, the relevant is commented 28 | out in this template, and call wm.get_screen().get_display().add_keybinding(). 29 | The keybinding function takes the name of the shortcut key in your 30 | schema, then a GSettings instance for that schema, which can be obtained with 31 | 'new GLib.Settings("org.pantheon.gala.plugins.my-plugin")', then some flags, for 32 | which you can almost always use 0, refer to the vapi for more details, and finally 33 | your function as arguments. Its delegate is: 34 | 35 | public delegate void KeyHandlerFunc (Meta.Display display, Meta.Screen screen, 36 | Meta.Window? window, X.Event event, Meta.KeyBinding binding); 37 | 38 | So it'd be something like 39 | 40 | void initialize (Gala.WindowManager wm) 41 | { 42 | [...] 43 | var display = wm.get_screen ().get_display (); 44 | var schema = new GLib.Settings ("org.pantheon.desktop.gala.plugins"); 45 | display.add_keybinding ("my-shortcut", schema, 0, my_handler); 46 | [...] 47 | } 48 | void my_handler (Meta.Display display, Meta.Screen screen, Meta.Window? window, 49 | X.Event event, Meta.KeyBinding binding) 50 | { 51 | print ("Shortcut hit! D:"); 52 | } 53 | void destroy () 54 | { 55 | wm.get_screen ().get_display ().remove_keybinding ("my-shortcut"); 56 | } 57 | 58 | Overriding default keybindings 59 | ------------------------------ 60 | Libmutter allows you to override existing shortcuts, which is a lot easier than 61 | adding new ones. All you have to do is: 62 | 63 | Keybinding.set_custom_handler ("shortcut-name", my_handler); 64 | 65 | The signature for my_handler is the same as above. 66 | 67 | More info 68 | --------- 69 | A great source for exploring the possibilities of mutter's API is scrolling through 70 | the mentioned mutter vapi. In some cases you can find documentation on particular 71 | functions in the mutter source code. Just grep for their C names. 72 | 73 | */ 74 | -------------------------------------------------------------------------------- /plugins/template/meson.build: -------------------------------------------------------------------------------- 1 | gala_template_sources = [ 2 | 'Main.vala', 3 | ] 4 | 5 | gala_template_lib = shared_library( 6 | 'gala-template', 7 | gala_template_sources, 8 | dependencies: [gala_dep, gala_base_dep], 9 | include_directories: config_inc_dir, 10 | install: false, 11 | install_dir: plugins_dir, 12 | install_rpath: mutter_typelib_dir, 13 | ) 14 | -------------------------------------------------------------------------------- /po/LINGUAS: -------------------------------------------------------------------------------- 1 | ae 2 | af 3 | ak 4 | am 5 | ar 6 | as 7 | ast 8 | av 9 | ay 10 | az 11 | ba 12 | be 13 | bg 14 | bh 15 | bi 16 | bm 17 | bn 18 | bo 19 | br 20 | bs 21 | ca 22 | ce 23 | ch 24 | ckb 25 | co 26 | cr 27 | cs 28 | cu 29 | cv 30 | cy 31 | da 32 | de 33 | dv 34 | dz 35 | ee 36 | el 37 | en_AU 38 | en_CA 39 | en_GB 40 | eo 41 | es 42 | et 43 | eu 44 | fa 45 | ff 46 | fi 47 | fj 48 | fo 49 | fr 50 | fr_CA 51 | fy 52 | ga 53 | gd 54 | gl 55 | gu 56 | gv 57 | ha 58 | he 59 | hi 60 | ho 61 | hr 62 | ht 63 | hu 64 | hy 65 | hz 66 | ia 67 | id 68 | ie 69 | ig 70 | ii 71 | ik 72 | io 73 | is 74 | it 75 | iu 76 | ja 77 | jv 78 | ka 79 | kg 80 | ki 81 | kj 82 | kk 83 | kl 84 | km 85 | kn 86 | ko 87 | kr 88 | ks 89 | ku 90 | kv 91 | kw 92 | ky 93 | la 94 | lb 95 | lg 96 | li 97 | ln 98 | lo 99 | lt 100 | lu 101 | lv 102 | mg 103 | mh 104 | mi 105 | mk 106 | ml 107 | mn 108 | mo 109 | mr 110 | ms 111 | mt 112 | my 113 | na 114 | nb 115 | nd 116 | ne 117 | ng 118 | nl 119 | nn 120 | no 121 | nr 122 | nv 123 | ny 124 | oc 125 | oj 126 | om 127 | or 128 | os 129 | pa 130 | pi 131 | pl 132 | ps 133 | pt 134 | pt_BR 135 | qu 136 | rm 137 | rn 138 | ro 139 | ru 140 | rue 141 | rw 142 | sa 143 | sc 144 | sd 145 | se 146 | sg 147 | si 148 | sk 149 | sl 150 | sm 151 | sma 152 | sn 153 | so 154 | sq 155 | sr 156 | ss 157 | st 158 | su 159 | sv 160 | sw 161 | szl 162 | ta 163 | te 164 | tg 165 | th 166 | ti 167 | tk 168 | tl 169 | tn 170 | to 171 | tr 172 | ts 173 | tt 174 | tw 175 | ty 176 | ug 177 | uk 178 | ur 179 | uz 180 | ve 181 | vi 182 | vo 183 | wa 184 | wo 185 | xh 186 | yi 187 | yo 188 | za 189 | zh 190 | zh_CN 191 | zh_HK 192 | zh_TW 193 | zu 194 | ace 195 | fil 196 | sr@latin 197 | aa 198 | ab 199 | gn 200 | an 201 | id_ID 202 | frp 203 | ca@valencia 204 | en_ZA 205 | pap 206 | sco 207 | -------------------------------------------------------------------------------- /po/POTFILES: -------------------------------------------------------------------------------- 1 | daemon/DBus.vala 2 | daemon-gtk3/BackgroundMenu.vala 3 | daemon-gtk3/DBus.vala 4 | daemon-gtk3/Main.vala 5 | daemon-gtk3/MonitorLabel.vala 6 | daemon-gtk3/WindowMenu.vala 7 | daemon-gtk3/Window.vala 8 | daemon/Main.vala 9 | daemon/MonitorLabel.vala 10 | daemon/WindowMenu.vala 11 | daemon/Window.vala 12 | data/gala.metainfo.xml.in 13 | data/gala-multitaskingview.desktop.in 14 | data/gala-other.desktop.in 15 | lib/ActivatableComponent.vala 16 | lib/AppCache.vala 17 | lib/AppSystem.vala 18 | lib/App.vala 19 | lib/BackgroundManager.vala 20 | lib/CanvasActor.vala 21 | lib/CloseButton.vala 22 | lib/Constants.vala 23 | lib/DragDropAction.vala 24 | lib/Drawing/BufferSurface.vala 25 | lib/Drawing/Canvas.vala 26 | lib/Drawing/Color.vala 27 | lib/Drawing/StyleManager.vala 28 | lib/Drawing/Utilities.vala 29 | lib/Plugin.vala 30 | lib/ShadowEffect.vala 31 | lib/Utils.vala 32 | lib/WindowIcon.vala 33 | lib/WindowManager.vala 34 | plugins/pip/Main.vala 35 | plugins/pip/PopupWindow.vala 36 | plugins/pip/SelectionArea.vala 37 | src/Background/Animation.vala 38 | src/Background/BackgroundCache.vala 39 | src/Background/BackgroundContainer.vala 40 | src/Background/BackgroundManager.vala 41 | src/Background/BackgroundSource.vala 42 | src/Background/Background.vala 43 | src/Background/BlurEffect.vala 44 | src/Background/SystemBackground.vala 45 | src/ColorFilters/ColorblindnessCorrectionEffect.vala 46 | src/ColorFilters/FilterManager.vala 47 | src/ColorFilters/MonochromeEffect.vala 48 | src/Dialogs/AccessDialog.vala 49 | src/Dialogs/CloseDialog.vala 50 | src/Dialogs/InhibitShortcutsDialog.vala 51 | src/DaemonManager.vala 52 | src/DBusAccelerator.vala 53 | src/DBus.vala 54 | src/DesktopIntegration.vala 55 | src/Gestures/GestureSettings.vala 56 | src/Gestures/Gesture.vala 57 | src/Gestures/ScrollBackend.vala 58 | src/Gestures/ToucheggBackend.vala 59 | src/HotCorners/Barrier.vala 60 | src/HotCorners/HotCornerManager.vala 61 | src/HotCorners/HotCorner.vala 62 | src/InternalUtils.vala 63 | src/KeyboardManager.vala 64 | src/Main.vala 65 | src/NotificationsManager.vala 66 | src/NotificationStack.vala 67 | src/PantheonShell.vala 68 | src/PluginManager.vala 69 | src/ScreenSaverManager.vala 70 | src/ScreenshotManager.vala 71 | src/SessionManager.vala 72 | src/ShellClients/HideTracker.vala 73 | src/ShellClients/ManagedClient.vala 74 | src/ShellClients/NotificationsClient.vala 75 | src/ShellClients/PanelWindow.vala 76 | src/ShellClients/ShellClientsManager.vala 77 | src/Widgets/DwellClickTimer.vala 78 | src/Widgets/MultitaskingView/IconGroup.vala 79 | src/Widgets/MultitaskingView/IconGroupContainer.vala 80 | src/Widgets/MultitaskingView/MonitorClone.vala 81 | src/Widgets/MultitaskingView/MultitaskingView.vala 82 | src/Widgets/MultitaskingView/StaticWindowClone.vala 83 | src/Widgets/MultitaskingView/StaticWindowContainer.vala 84 | src/Widgets/MultitaskingView/Tooltip.vala 85 | src/Widgets/MultitaskingView/WindowClone.vala 86 | src/Widgets/MultitaskingView/WindowCloneContainer.vala 87 | src/Widgets/MultitaskingView/WindowIconActor.vala 88 | src/Widgets/MultitaskingView/WorkspaceClone.vala 89 | src/Widgets/MultitaskingView/WorkspaceInsertThumb.vala 90 | src/Widgets/MultitaskingView/WorkspaceRow.vala 91 | src/Widgets/PixelPicker.vala 92 | src/Widgets/PointerLocator.vala 93 | src/Widgets/SelectionArea.vala 94 | src/Widgets/SessionLocker.vala 95 | src/Widgets/WindowOverview.vala 96 | src/Widgets/WindowSwitcher/WindowSwitcherIcon.vala 97 | src/Widgets/WindowSwitcher/WindowSwitcher.vala 98 | src/WindowListener.vala 99 | src/WindowManager.vala 100 | src/WindowStateSaver.vala 101 | src/WindowTracker.vala 102 | src/WorkspaceManager.vala 103 | src/Zoom.vala 104 | -------------------------------------------------------------------------------- /po/meson.build: -------------------------------------------------------------------------------- 1 | i18n.gettext( 2 | meson.project_name(), 3 | preset: 'glib', 4 | args: [ 5 | '--default-domain=' + meson.project_name(), 6 | '--package-version=' + meson.project_version(), 7 | '--copyright-holder=The Gala Developers', 8 | '--msgid-bugs-address=https://github.com/elementary/gala/issues', 9 | ], 10 | ) 11 | -------------------------------------------------------------------------------- /protocol/meson.build: -------------------------------------------------------------------------------- 1 | dep_scanner = dependency('wayland-scanner', native: true) 2 | prog_scanner = find_program(dep_scanner.get_variable(pkgconfig: 'wayland_scanner')) 3 | 4 | protocol_file = files('pantheon-desktop-shell-v1.xml') 5 | 6 | pantheon_desktop_shell_sources = [] 7 | pantheon_desktop_shell_sources += custom_target( 8 | 'pantheon-desktop-shell-server-protocol.h', 9 | command: [ prog_scanner, 'server-header', '@INPUT@', '@OUTPUT@' ], 10 | input: protocol_file, 11 | output: 'pantheon-desktop-shell-server-protocol.h', 12 | ) 13 | 14 | output_type = 'private-code' 15 | if dep_scanner.version().version_compare('< 1.14.91') 16 | output_type = 'code' 17 | endif 18 | pantheon_desktop_shell_sources += custom_target( 19 | 'pantheon-desktop-shell-protocol.c', 20 | command: [ prog_scanner, output_type, '@INPUT@', '@OUTPUT@' ], 21 | input: protocol_file, 22 | output: 'pantheon-desktop-shell-protocol.c', 23 | ) 24 | 25 | pantheon_desktop_shell_dep = declare_dependency( 26 | dependencies: [ 27 | vala.find_library('pantheon-desktop-shell', dirs: meson.current_source_dir()), 28 | dependency('wayland-server'), 29 | ], 30 | include_directories: include_directories('.'), 31 | sources: pantheon_desktop_shell_sources 32 | ) 33 | -------------------------------------------------------------------------------- /protocol/pantheon-desktop-shell.deps: -------------------------------------------------------------------------------- 1 | wayland-server 2 | -------------------------------------------------------------------------------- /protocol/pantheon-desktop-shell.vapi: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 elementary, Inc. 3 | * Copyright 2023 Corentin Noël 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | */ 6 | 7 | namespace Pantheon.Desktop { 8 | [CCode (cheader_filename = "pantheon-desktop-shell-server-protocol.h", cname = "struct io_elementary_pantheon_shell_v1_interface")] 9 | public struct ShellInterface { 10 | [CCode (cheader_filename = "pantheon-desktop-shell-server-protocol.h", cname = "io_elementary_pantheon_shell_v1_interface")] 11 | public static Wl.Interface iface; 12 | public Pantheon.Desktop.GetPanel get_panel; 13 | public Pantheon.Desktop.GetWidget get_widget; 14 | public Pantheon.Desktop.GetExtendedBehavior get_extended_behavior; 15 | 16 | } 17 | 18 | [CCode (cheader_filename = "pantheon-desktop-shell-server-protocol.h", cname = "enum io_elementary_pantheon_panel_v1_anchor", cprefix="IO_ELEMENTARY_PANTHEON_PANEL_V1_ANCHOR_", has_type_id = false)] 19 | public enum Anchor { 20 | TOP, 21 | BOTTOM, 22 | LEFT, 23 | RIGHT, 24 | } 25 | 26 | [CCode (cheader_filename = "pantheon-desktop-shell-server-protocol.h", cname = "enum io_elementary_pantheon_panel_v1_hide_mode", cprefix="IO_ELEMENTARY_PANTHEON_PANEL_V1_HIDE_MODE_", has_type_id = false)] 27 | public enum HideMode { 28 | NEVER, 29 | MAXIMIZED_FOCUS_WINDOW, 30 | OVERLAPPING_FOCUS_WINDOW, 31 | OVERLAPPING_WINDOW, 32 | ALWAYS 33 | } 34 | 35 | [CCode (cheader_filename = "pantheon-desktop-shell-server-protocol.h", cname = "struct io_elementary_pantheon_panel_v1_interface")] 36 | public struct PanelInterface { 37 | [CCode (cheader_filename = "pantheon-desktop-shell-server-protocol.h", cname = "io_elementary_pantheon_panel_v1_interface")] 38 | public static Wl.Interface iface; 39 | public Destroy destroy; 40 | public SetAnchor set_anchor; 41 | public Focus focus; 42 | public SetSize set_size; 43 | public SetHideMode set_hide_mode; 44 | } 45 | 46 | [CCode (cheader_filename = "pantheon-desktop-shell-server-protocol.h", cname = "struct io_elementary_pantheon_widget_v1_interface")] 47 | public struct WidgetInterface { 48 | [CCode (cheader_filename = "pantheon-desktop-shell-server-protocol.h", cname = "io_elementary_pantheon_widget_v1_interface")] 49 | public static Wl.Interface iface; 50 | public Destroy destroy; 51 | } 52 | 53 | [CCode (cheader_filename = "pantheon-desktop-shell-server-protocol.h", cname = "struct io_elementary_pantheon_extended_behavior_v1_interface")] 54 | public struct ExtendedBehaviorInterface { 55 | [CCode (cheader_filename = "pantheon-desktop-shell-server-protocol.h", cname = "io_elementary_pantheon_extended_behavior_v1_interface")] 56 | public static Wl.Interface iface; 57 | public Destroy destroy; 58 | public SetKeepAbove set_keep_above; 59 | public MakeCentered make_centered; 60 | public Focus focus; 61 | } 62 | 63 | [CCode (has_target = false, has_typedef = false)] 64 | public delegate void GetPanel (Wl.Client client, Wl.Resource resource, uint32 output, Wl.Resource surface); 65 | [CCode (has_target = false, has_typedef = false)] 66 | public delegate void GetWidget (Wl.Client client, Wl.Resource resource, uint32 output, Wl.Resource surface); 67 | [CCode (has_target = false, has_typedef = false)] 68 | public delegate void GetExtendedBehavior (Wl.Client client, Wl.Resource resource, uint32 output, Wl.Resource surface); 69 | [CCode (has_target = false, has_typedef = false)] 70 | public delegate void SetAnchor (Wl.Client client, Wl.Resource resource, [CCode (type = "uint32_t")] Anchor anchor); 71 | [CCode (has_target = false, has_typedef = false)] 72 | public delegate void Focus (Wl.Client client, Wl.Resource resource); 73 | [CCode (has_target = false, has_typedef = false)] 74 | public delegate void SetSize (Wl.Client client, Wl.Resource resource, int width, int height); 75 | [CCode (has_target = false, has_typedef = false)] 76 | public delegate void SetHideMode (Wl.Client client, Wl.Resource resource, [CCode (type = "uint32_t")] HideMode hide_mode); 77 | [CCode (has_target = false, has_typedef = false)] 78 | public delegate void SetKeepAbove (Wl.Client client, Wl.Resource resource); 79 | [CCode (has_target = false, has_typedef = false)] 80 | public delegate void MakeCentered (Wl.Client client, Wl.Resource resource); 81 | [CCode (has_target = false, has_typedef = false)] 82 | public delegate void Destroy (Wl.Client client, Wl.Resource resource); 83 | } 84 | -------------------------------------------------------------------------------- /src/Background/Animation.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2024 elementary, Inc. (https://elementary.io) 4 | * 2014 Tom Beckmann 5 | */ 6 | 7 | public class Gala.Animation : Object { 8 | public string filename { get; construct; } 9 | public string[] key_frame_files { get; private set; default = {}; } 10 | public double transition_progress { get; private set; default = 0.0; } 11 | public double transition_duration { get; private set; default = 0.0; } 12 | public bool loaded { get; private set; default = false; } 13 | 14 | private Gnome.BGSlideShow? show = null; 15 | 16 | public Animation (string filename) { 17 | Object (filename: filename); 18 | } 19 | 20 | public async void load () { 21 | show = new Gnome.BGSlideShow (filename); 22 | 23 | show.load_async (null, (obj, res) => { 24 | loaded = true; 25 | 26 | load.callback (); 27 | }); 28 | 29 | yield; 30 | } 31 | 32 | public void update (Mtk.Rectangle monitor) { 33 | string[] key_frame_files = {}; 34 | 35 | if (show == null) { 36 | return; 37 | } 38 | 39 | if (show.get_num_slides () < 1) { 40 | return; 41 | } 42 | 43 | double progress, duration; 44 | bool is_fixed; 45 | string file1, file2; 46 | show.get_current_slide (monitor.width, monitor.height, out progress, out duration, out is_fixed, out file1, out file2); 47 | 48 | transition_duration = duration; 49 | transition_progress = progress; 50 | 51 | if (file1 != null) { 52 | key_frame_files += file1; 53 | } 54 | 55 | if (file2 != null) { 56 | key_frame_files += file2; 57 | } 58 | 59 | this.key_frame_files = key_frame_files; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/Background/BackgroundCache.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2014 Tom Beckmann 4 | * 2025 elementary, Inc. (https://elementary.io) 5 | */ 6 | 7 | public class Gala.BackgroundCache : Object { 8 | private static BackgroundCache? instance = null; 9 | 10 | public static unowned BackgroundCache get_default () { 11 | if (instance == null) 12 | instance = new BackgroundCache (); 13 | 14 | return instance; 15 | } 16 | 17 | public signal void file_changed (string filename); 18 | 19 | private Gee.HashMap file_monitors; 20 | private BackgroundSource background_source; 21 | 22 | private Animation animation; 23 | 24 | public BackgroundCache () { 25 | Object (); 26 | } 27 | 28 | construct { 29 | file_monitors = new Gee.HashMap (); 30 | } 31 | 32 | public void monitor_file (string filename) { 33 | if (file_monitors.has_key (filename)) 34 | return; 35 | 36 | var file = File.new_for_path (filename); 37 | try { 38 | var monitor = file.monitor (FileMonitorFlags.NONE, null); 39 | monitor.changed.connect (() => { 40 | file_changed (filename); 41 | }); 42 | 43 | file_monitors[filename] = monitor; 44 | } catch (Error e) { 45 | warning ("Failed to monitor %s: %s", filename, e.message); 46 | } 47 | } 48 | 49 | public async Animation get_animation (string filename) { 50 | if (animation != null && animation.filename == filename) { 51 | Idle.add (() => { 52 | get_animation.callback (); 53 | return Source.REMOVE; 54 | }); 55 | yield; 56 | 57 | return animation; 58 | } 59 | 60 | var animation = new Animation (filename); 61 | 62 | yield animation.load (); 63 | 64 | Idle.add (() => { 65 | get_animation.callback (); 66 | return Source.REMOVE; 67 | }); 68 | yield; 69 | 70 | return animation; 71 | } 72 | 73 | public BackgroundSource get_background_source (Meta.Display display) { 74 | if (background_source == null) { 75 | background_source = new BackgroundSource (display); 76 | background_source.use_count = 1; 77 | } else 78 | background_source.use_count++; 79 | 80 | return background_source; 81 | } 82 | 83 | public void release_background_source () { 84 | if (--background_source.use_count == 0) { 85 | background_source.destroy (); 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/Background/BackgroundContainer.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2013 Tom Beckmann 4 | * 2013 Rico Tzschichholz 5 | * 2025 elementary, Inc. (https://elementary.io) 6 | */ 7 | 8 | public class Gala.BackgroundContainer : Meta.BackgroundGroup { 9 | public signal void changed (); 10 | public signal void show_background_menu (int x, int y); 11 | 12 | public Meta.Display display { get; construct; } 13 | 14 | public BackgroundContainer (Meta.Display display) { 15 | Object (display: display); 16 | } 17 | 18 | construct { 19 | unowned var monitor_manager = display.get_context ().get_backend ().get_monitor_manager (); 20 | monitor_manager.monitors_changed.connect (update); 21 | 22 | reactive = true; 23 | button_release_event.connect ((event) => { 24 | float x, y; 25 | event.get_coords (out x, out y); 26 | if (event.get_button () == Clutter.Button.SECONDARY) { 27 | show_background_menu ((int)x, (int)y); 28 | } 29 | }); 30 | 31 | #if HAS_MUTTER47 32 | background_color = Cogl.Color.from_string ("Black"); 33 | #else 34 | background_color = Clutter.Color.from_string ("Black"); 35 | #endif 36 | 37 | update (); 38 | } 39 | 40 | ~BackgroundContainer () { 41 | unowned var monitor_manager = display.get_context ().get_backend ().get_monitor_manager (); 42 | monitor_manager.monitors_changed.disconnect (update); 43 | } 44 | 45 | private void update () { 46 | var reference_child = (get_child_at_index (0) as BackgroundManager); 47 | if (reference_child != null) 48 | reference_child.changed.disconnect (background_changed); 49 | 50 | destroy_all_children (); 51 | 52 | for (var i = 0; i < display.get_n_monitors (); i++) { 53 | var background = new BackgroundManager (display, i); 54 | 55 | add_child (background); 56 | 57 | if (i == 0) 58 | background.changed.connect (background_changed); 59 | } 60 | } 61 | 62 | private void background_changed () { 63 | changed (); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/Background/SystemBackground.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Tom Beckmann 3 | * Copyright 2023-2024 elementary, Inc. 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | */ 6 | 7 | public class Gala.SystemBackground : GLib.Object { 8 | public Meta.BackgroundActor background_actor { get; construct; } 9 | 10 | public SystemBackground (Meta.Display display) { 11 | Object (background_actor: new Meta.BackgroundActor (display, 0)); 12 | } 13 | 14 | construct { 15 | var system_background = new Meta.Background (background_actor.meta_display); 16 | system_background.set_color ({ 0x2e, 0x34, 0x36, 0xff }); 17 | 18 | ((Meta.BackgroundContent) background_actor.content).background = system_background; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/ColorFilters/ColorblindnessCorrectionEffect.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 elementary, Inc. 3 | * SPDX-License-Identifier: GPL-3.0-or-later 4 | */ 5 | 6 | public class Gala.ColorblindnessCorrectionEffect : Clutter.ShaderEffect { 7 | public const string EFFECT_NAME = "colorblindness-correction-filter"; 8 | 9 | private int _mode; 10 | public int mode { 11 | get { return _mode; } 12 | construct set { 13 | _mode = value; 14 | set_uniform_value ("COLORBLIND_MODE", _mode); 15 | } 16 | } 17 | private double _strength; 18 | public double strength { 19 | get { return _strength; } 20 | construct set { 21 | _strength = value; 22 | 23 | set_uniform_value ("STRENGTH", value); 24 | queue_repaint (); 25 | } 26 | } 27 | 28 | /* 29 | * Used for fading in and out the effect, since you can't add transitions to effects. 30 | */ 31 | public Clutter.Actor? transition_actor { get; set; default = null; } 32 | 33 | public ColorblindnessCorrectionEffect (int mode, double strength) { 34 | Object ( 35 | shader_type: Clutter.ShaderType.FRAGMENT_SHADER, 36 | mode: mode, 37 | strength: strength 38 | ); 39 | 40 | try { 41 | var bytes = GLib.resources_lookup_data ("/io/elementary/desktop/gala/shaders/colorblindness-correction.vert", GLib.ResourceLookupFlags.NONE); 42 | set_shader_source ((string) bytes.get_data ()); 43 | } catch (Error e) { 44 | critical ("Unable to load colorblindness-correction.vert: %s", e.message); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/ColorFilters/MonochromeEffect.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 elementary, Inc. 3 | * SPDX-License-Identifier: GPL-3.0-or-later 4 | */ 5 | 6 | public class Gala.MonochromeEffect : Clutter.ShaderEffect { 7 | public const string EFFECT_NAME = "monochrome-filter"; 8 | 9 | private double _strength; 10 | public double strength { 11 | get { return _strength; } 12 | construct set { 13 | _strength = value; 14 | 15 | set_uniform_value ("STRENGTH", value); 16 | queue_repaint (); 17 | } 18 | } 19 | 20 | /* 21 | * Used for fading in and out the effect, since you can't add transitions to effects. 22 | */ 23 | public Clutter.Actor? transition_actor { get; set; default = null; } 24 | 25 | public MonochromeEffect (double strength) { 26 | Object ( 27 | shader_type: Clutter.ShaderType.FRAGMENT_SHADER, 28 | strength: strength 29 | ); 30 | 31 | try { 32 | var bytes = GLib.resources_lookup_data ("/io/elementary/desktop/gala/shaders/monochrome.vert", GLib.ResourceLookupFlags.NONE); 33 | set_shader_source ((string) bytes.get_data ()); 34 | } catch (Error e) { 35 | critical ("Unable to load monochrome.vert: %s", e.message); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/DBus.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2024-2025 elementary, Inc. (https://elementary.io) 4 | * 2012-2014 Tom Beckmann 5 | * 2012-2014 Jacob Parker 6 | */ 7 | 8 | [DBus (name="org.pantheon.gala")] 9 | public class Gala.DBus { 10 | private static DBus? instance; 11 | private static WindowManagerGala wm; 12 | 13 | [DBus (visible = false)] 14 | public static void init (WindowManagerGala _wm, NotificationsManager notifications_manager, ScreenshotManager screenshot_manager) { 15 | wm = _wm; 16 | 17 | Bus.own_name (BusType.SESSION, "org.pantheon.gala", BusNameOwnerFlags.NONE, 18 | (connection) => { 19 | if (instance == null) 20 | instance = new DBus (); 21 | 22 | try { 23 | connection.register_object ("/org/pantheon/gala", instance); 24 | } catch (Error e) { warning (e.message); } 25 | 26 | try { 27 | connection.register_object ("/org/pantheon/gala/DesktopInterface", new DesktopIntegration (wm)); 28 | } catch (Error e) { warning (e.message); } 29 | }, 30 | () => {}, 31 | () => warning ("Could not acquire name\n") ); 32 | 33 | Bus.own_name (BusType.SESSION, "org.gnome.Shell", BusNameOwnerFlags.NONE, 34 | (connection) => { 35 | try { 36 | connection.register_object ("/org/gnome/Shell", new DBusAccelerator (wm.get_display (), notifications_manager)); 37 | connection.register_object ("/org/gnome/Shell/Screenshot", screenshot_manager); 38 | } catch (Error e) { warning (e.message); } 39 | }, 40 | () => {}, 41 | () => critical ("Could not acquire name") ); 42 | 43 | Bus.own_name (BusType.SESSION, "org.gnome.Shell.Screenshot", BusNameOwnerFlags.REPLACE, 44 | () => {}, 45 | () => {}, 46 | () => critical ("Could not acquire name") ); 47 | 48 | Bus.own_name (BusType.SESSION, "org.gnome.SessionManager.EndSessionDialog", BusNameOwnerFlags.NONE, 49 | (connection) => { 50 | try { 51 | connection.register_object ("/org/gnome/SessionManager/EndSessionDialog", SessionManager.init ()); 52 | } catch (Error e) { warning (e.message); } 53 | }, 54 | () => {}, 55 | () => critical ("Could not acquire name") ); 56 | 57 | Bus.own_name (BusType.SESSION, "org.gnome.ScreenSaver", BusNameOwnerFlags.REPLACE, 58 | (connection) => { 59 | try { 60 | connection.register_object ("/org/gnome/ScreenSaver", wm.screensaver); 61 | } catch (Error e) { warning (e.message); } 62 | }, 63 | () => {}, 64 | () => critical ("Could not acquire ScreenSaver bus") ); 65 | } 66 | 67 | public void perform_action (ActionType type) throws DBusError, IOError { 68 | wm.perform_action (type); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/Dialogs/AccessDialog.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2021-2023, 2025 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | public class Gala.AccessDialog : Object { 7 | [DBus (name = "org.freedesktop.impl.portal.Access")] 8 | protected interface AccessPortal : Object { 9 | [DBus (timeout = 2147483647)] // timeout = int.MAX; value got from 10 | public abstract async void access_dialog ( 11 | ObjectPath request_path, 12 | string app_id, 13 | string window_handle, 14 | string title, 15 | string sub_title, 16 | string body, 17 | HashTable options, 18 | out uint response 19 | ) throws IOError, DBusError; 20 | } 21 | 22 | [DBus (name = "org.freedesktop.impl.portal.Request")] 23 | private interface Request : Object { 24 | public abstract void close () throws DBusError, IOError; 25 | } 26 | 27 | public signal void response (uint response); 28 | 29 | public Meta.Window parent { owned get; construct set; } 30 | 31 | public string title { get; construct set; } 32 | public string body { get; construct set; } 33 | public string icon { get; construct set; } 34 | public string accept_label { get; set; } 35 | public string deny_label { get; set; } 36 | 37 | private const string PANTHEON_PORTAL_NAME = "org.freedesktop.impl.portal.desktop.pantheon"; 38 | private const string FDO_PORTAL_PATH = "/org/freedesktop/portal/desktop"; 39 | private const string GALA_DIALOG_PATH = "/io/elementary/gala/dialog"; 40 | 41 | protected static AccessPortal? portal = null; 42 | protected ObjectPath? path = null; 43 | 44 | public static void watch_portal () { 45 | Bus.watch_name (BusType.SESSION, PANTHEON_PORTAL_NAME, BusNameWatcherFlags.NONE, 46 | () => { 47 | try { 48 | portal = Bus.get_proxy_sync (BusType.SESSION, PANTHEON_PORTAL_NAME, FDO_PORTAL_PATH); 49 | } catch (Error e) { 50 | warning ("can't reach portal session: %s", e.message); 51 | } 52 | }, 53 | () => { 54 | portal = null; 55 | } 56 | ); 57 | } 58 | 59 | public AccessDialog (string title, string body, string icon) { 60 | Object (title: title, body: body, icon: icon); 61 | } 62 | 63 | [Signal (run = "first")] 64 | public virtual signal void show () { 65 | if (portal == null) { 66 | return; 67 | } 68 | 69 | path = new ObjectPath (GALA_DIALOG_PATH + "/%i".printf (Random.int_range (0, int.MAX))); 70 | string parent_handler = ""; 71 | var app_id = ""; 72 | 73 | if (parent != null) { 74 | if (parent.get_client_type () == Meta.WindowClientType.X11) { 75 | #if HAS_MUTTER46 76 | unowned Meta.Display display = parent.get_display (); 77 | unowned Meta.X11Display x11display = display.get_x11_display (); 78 | parent_handler = "x11:%x".printf ((uint) x11display.lookup_xwindow (parent)); 79 | #else 80 | parent_handler = "x11:%x".printf ((uint) parent.get_xwindow ()); 81 | #endif 82 | //TODO: wayland support 83 | } 84 | 85 | app_id = parent.get_sandboxed_app_id () ?? ""; 86 | } 87 | 88 | var options = new HashTable (str_hash, str_equal); 89 | options["grant_label"] = accept_label; 90 | options["deny_label"] = deny_label; 91 | options["icon"] = icon; 92 | 93 | if (this is CloseDialog) { 94 | options["destructive"] = true; 95 | } 96 | 97 | portal.access_dialog.begin (path, app_id, parent_handler, title, body, "", options, (obj, res) => { 98 | uint ret; 99 | 100 | try { 101 | ((AccessPortal) obj).access_dialog.end (res, out ret); 102 | } catch (Error e) { 103 | warning (e.message); 104 | ret = 2; 105 | } 106 | 107 | on_response (ret); 108 | path = null; 109 | }); 110 | } 111 | 112 | public void close () { 113 | try { 114 | Bus.get_proxy_sync (BusType.SESSION, PANTHEON_PORTAL_NAME, path).close (); 115 | path = null; 116 | } catch (Error e) { 117 | warning (e.message); 118 | } 119 | } 120 | 121 | protected virtual void on_response (uint response_id) { 122 | response (response_id); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/Dialogs/CloseDialog.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2021-2023, 2025 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | public class Gala.CloseDialog : AccessDialog, Meta.CloseDialog { 7 | public Meta.Window window { 8 | owned get { return parent; } 9 | construct { parent = value; } 10 | } 11 | 12 | public App app { get; construct; } 13 | 14 | public CloseDialog (Gala.App app, Meta.Window window) { 15 | Object (app: app, window: window); 16 | } 17 | 18 | construct { 19 | icon = "computer-fail"; 20 | 21 | var window_title = app.name; 22 | if (window_title != null) { 23 | title = _("“%s” is not responding").printf (window_title); 24 | } else { 25 | title = _("Application is not responding"); 26 | } 27 | 28 | body = _("You may choose to wait a short while for the application to continue, or force it to quit entirely."); 29 | accept_label = _("Force Quit"); 30 | deny_label = _("Wait"); 31 | } 32 | 33 | public override void show () { 34 | if (path != null) { 35 | return; 36 | } 37 | 38 | try { 39 | var our_pid = new Credentials ().get_unix_pid (); 40 | if (our_pid == window.get_pid ()) { 41 | critical ("We have an unresponsive window somewhere. Mutter wants to end its own process. Don't let it."); 42 | // In all seriousness this sounds bad, but can happen if one of our WaylandClients gets unresponsive. 43 | on_response (1); 44 | return; 45 | } 46 | } catch (Error e) { 47 | warning ("Failed to safeguard kill pid: %s", e.message); 48 | } 49 | 50 | base.show (); 51 | } 52 | 53 | public void hide () { 54 | if (path != null) { 55 | close (); 56 | } 57 | } 58 | 59 | public void focus () { 60 | window.foreach_transient ((w) => { 61 | if (w.get_role () == "AccessDialog") { 62 | w.activate (w.get_display ().get_current_time ()); 63 | return false; 64 | } 65 | 66 | return true; 67 | }); 68 | } 69 | 70 | protected override void on_response (uint response_id) { 71 | if (response_id == 0) { 72 | base.response (Meta.CloseDialogResponse.FORCE_CLOSE); 73 | } else { 74 | base.response (Meta.CloseDialogResponse.WAIT); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/Dialogs/InhibitShortcutsDialog.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2021-2023, 2025 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | public class Gala.InhibitShortcutsDialog : AccessDialog, Meta.InhibitShortcutsDialog { 7 | public Meta.Window window { 8 | owned get { return parent; } 9 | construct { parent = value; } 10 | } 11 | 12 | public App app { get; construct; } 13 | 14 | public InhibitShortcutsDialog (Gala.App app, Meta.Window window) { 15 | Object (app: app, window: window); 16 | } 17 | 18 | construct { 19 | icon = "preferences-desktop-keyboard"; 20 | 21 | var window_title = app.name; 22 | if (window_title != null) { 23 | title = _("“%s” wants to inhibit system shortcuts").printf (window_title); 24 | } else { 25 | title = _("An application wants to inhibit system shortcuts"); 26 | } 27 | 28 | body = _("All system shortcuts will be redirected to the application."); 29 | accept_label = _("Allow"); 30 | deny_label = _("Deny"); 31 | } 32 | 33 | public override void show () { 34 | if (path != null) { 35 | return; 36 | } 37 | 38 | if (app.id == "io.elementary.settings.desktop" || // Naive check to always allow inhibiting by our settings app. This is needed for setting custom shortcuts 39 | ShellClientsManager.get_instance ().is_positioned_window (window) // Certain windows (e.g. centered ones) may want to disable move via super + drag 40 | ) { 41 | on_response (0); 42 | return; 43 | } 44 | 45 | base.show (); 46 | } 47 | 48 | public void hide () { 49 | if (path != null) { 50 | close (); 51 | } 52 | } 53 | 54 | protected override void on_response (uint response_id) { 55 | if (response_id == 0) { 56 | base.response (Meta.InhibitShortcutsDialogResponse.ALLOW); 57 | } else { 58 | base.response (Meta.InhibitShortcutsDialogResponse.DENY); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/Gestures/ActorTarget.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 elementary, Inc. (https://elementary.io) 3 | * SPDX-License-Identifier: GPL-3.0-or-later 4 | * 5 | * Authored by: Leonhard Kargl 6 | */ 7 | 8 | /** 9 | * An {@link GestureTarget} implementation that derives from a {@link Clutter.Actor}. 10 | * It will propagate gesture events to all direct descendants that are also {@link ActorTarget}s. 11 | * If a new child (or target via {@link add_target}) is added, its progress will be synced. 12 | */ 13 | public class Gala.ActorTarget : Clutter.Actor, GestureTarget { 14 | public Clutter.Actor? actor { 15 | get { 16 | return this; 17 | } 18 | } 19 | 20 | public bool animating { get { return ongoing_animations > 0; } } 21 | 22 | private double[] current_progress; 23 | private double[] current_commit; 24 | private Gee.List targets; 25 | 26 | private int ongoing_animations = 0; 27 | 28 | construct { 29 | current_progress = new double[GestureAction.N_ACTIONS]; 30 | current_commit = new double[GestureAction.N_ACTIONS]; 31 | targets = new Gee.ArrayList (); 32 | 33 | child_added.connect (on_child_added); 34 | } 35 | 36 | private void sync_target (GestureTarget target) { 37 | for (int action = 0; action < current_progress.length; action++) { 38 | target.propagate (COMMIT, action, current_commit[action]); 39 | target.propagate (UPDATE, action, current_progress[action]); 40 | } 41 | } 42 | 43 | public void add_target (GestureTarget target) { 44 | targets.add (target); 45 | sync_target (target); 46 | } 47 | 48 | public void remove_target (GestureTarget target) { 49 | targets.remove (target); 50 | } 51 | 52 | public void remove_all_targets () { 53 | targets.clear (); 54 | } 55 | 56 | public double get_current_progress (GestureAction action) { 57 | return current_progress[action]; 58 | } 59 | 60 | public double get_current_commit (GestureAction action) { 61 | return current_commit[action]; 62 | } 63 | 64 | public virtual void start_progress (GestureAction action) {} 65 | public virtual void update_progress (GestureAction action, double progress) {} 66 | public virtual void commit_progress (GestureAction action, double to) {} 67 | public virtual void end_progress (GestureAction action) {} 68 | 69 | public override void propagate (UpdateType update_type, GestureAction action, double progress) { 70 | if (update_type == COMMIT) { 71 | current_commit[action] = progress; 72 | } else { 73 | current_progress[action] = progress; 74 | } 75 | 76 | foreach (var target in targets) { 77 | target.propagate (update_type, action, progress); 78 | } 79 | 80 | for (var child = get_first_child (); child != null; child = child.get_next_sibling ()) { 81 | if (child is ActorTarget) { 82 | child.propagate (update_type, action, progress); 83 | } 84 | } 85 | 86 | switch (update_type) { 87 | case START: 88 | ongoing_animations++; 89 | start_progress (action); 90 | break; 91 | case UPDATE: 92 | update_progress (action, progress); 93 | break; 94 | case COMMIT: 95 | commit_progress (action, progress); 96 | break; 97 | case END: 98 | ongoing_animations--; 99 | end_progress (action); 100 | break; 101 | } 102 | } 103 | 104 | private void on_child_added (Clutter.Actor child) { 105 | if (child is ActorTarget) { 106 | sync_target ((GestureTarget) child); 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/Gestures/Gesture.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 elementary, Inc (https://elementary.io) 3 | * 2021 José Expósito 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | namespace Gala { 20 | /** 21 | * Physical direction of the gesture. This direction doesn't follow natural scroll preferences. 22 | */ 23 | public enum GestureDirection { 24 | UNKNOWN = 0, 25 | 26 | // GestureType.SWIPE and GestureType.SCROLL 27 | UP = 1, 28 | DOWN = 2, 29 | LEFT = 3, 30 | RIGHT = 4, 31 | 32 | // GestureType.PINCH 33 | IN = 5, 34 | OUT = 6, 35 | } 36 | 37 | public class Gesture { 38 | public const float INVALID_COORD = float.MAX; 39 | 40 | public Clutter.EventType type; 41 | public GestureDirection direction; 42 | public int fingers; 43 | public Clutter.InputDeviceType performed_on_device_type; 44 | 45 | /** 46 | * The x coordinate of the initial contact point for the gesture. 47 | * Doesn't have to be set. In that case it is set to {@link INVALID_COORD}. 48 | * Currently the only backend not setting this is {@link GestureTracker.enable_touchpad}. 49 | */ 50 | public float origin_x = INVALID_COORD; 51 | 52 | /** 53 | * The y coordinate of the initial contact point for the gesture. 54 | * Doesn't have to be set. In that case it is set to {@link INVALID_COORD}. 55 | * Currently the only backend not setting this is {@link GestureTracker.enable_touchpad}. 56 | */ 57 | public float origin_y = INVALID_COORD; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Gestures/GestureBackend.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 elementary, Inc. (https://elementary.io) 3 | * SPDX-License-Identifier: GPL-3.0-or-later 4 | * 5 | * Authored by: Leonhard Kargl 6 | */ 7 | 8 | public interface Gala.GestureBackend : Object { 9 | public signal bool on_gesture_detected (Gesture gesture, uint32 timestamp); 10 | public signal void on_begin (double delta, uint64 time); 11 | public signal void on_update (double delta, uint64 time); 12 | public signal void on_end (double delta, uint64 time); 13 | 14 | public virtual void prepare_gesture_handling () { } 15 | 16 | /** 17 | * The gesture should be cancelled. The implementation should stop emitting 18 | * signals and reset any internal state. In particular it should not emit on_end. 19 | * The implementation has to make sure that any further events from the same gesture will 20 | * will be ignored. Once the gesture ends a new gesture should be treated as usual. 21 | */ 22 | public virtual void cancel_gesture () { } 23 | } 24 | -------------------------------------------------------------------------------- /src/Gestures/GestureTarget.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 elementary, Inc. (https://elementary.io) 3 | * SPDX-License-Identifier: GPL-3.0-or-later 4 | * 5 | * Authored by: Leonhard Kargl 6 | */ 7 | 8 | public interface Gala.GestureTarget : Object { 9 | public enum UpdateType { 10 | START, 11 | UPDATE, 12 | COMMIT, 13 | END 14 | } 15 | 16 | /** 17 | * The actor manipulated by the gesture. The associated frame clock 18 | * will be used for animation timelines. 19 | */ 20 | public abstract Clutter.Actor? actor { get; } 21 | 22 | public virtual void propagate (UpdateType update_type, GestureAction action, double progress) { } 23 | } 24 | -------------------------------------------------------------------------------- /src/Gestures/PropertyTarget.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 elementary, Inc. (https://elementary.io) 3 | * SPDX-License-Identifier: GPL-3.0-or-later 4 | * 5 | * Authored by: Leonhard Kargl 6 | */ 7 | 8 | public class Gala.PropertyTarget : Object, GestureTarget { 9 | public GestureAction action { get; construct; } 10 | 11 | //we don't want to hold a strong reference to the actor because we might've been added to it which would form a reference cycle 12 | private weak Clutter.Actor? _actor; 13 | public Clutter.Actor? actor { get { return _actor; } } 14 | 15 | public string property { get; construct; } 16 | 17 | public Clutter.Interval interval { get; construct; } 18 | 19 | public PropertyTarget (GestureAction action, Clutter.Actor actor, string property, Type value_type, Value from_value, Value to_value) { 20 | Object (action: action, property: property, interval: new Clutter.Interval.with_values (value_type, from_value, to_value)); 21 | 22 | _actor = actor; 23 | _actor.destroy.connect (() => _actor = null); 24 | } 25 | 26 | public override void propagate (UpdateType update_type, GestureAction action, double progress) { 27 | if (update_type != UPDATE || action != this.action) { 28 | return; 29 | } 30 | 31 | actor.set_property (property, interval.compute (progress)); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Gestures/RootTarget.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 elementary, Inc. (https://elementary.io) 3 | * SPDX-License-Identifier: GPL-3.0-or-later 4 | * 5 | * Authored by: Leonhard Kargl 6 | */ 7 | 8 | public interface Gala.RootTarget : Object, GestureTarget { 9 | public void add_gesture_controller (GestureController controller) requires (controller.target == null) { 10 | controller.attached (this); 11 | weak_ref (controller.detached); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/HotCorners/Barrier.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 elementary, Inc. (https://elementary.io) 3 | * SPDX-License-Identifier: GPL-3.0-or-later 4 | */ 5 | 6 | /** 7 | * A pointer barrier supporting pressured activation. 8 | */ 9 | public class Gala.Barrier : Object { 10 | public signal void trigger (); 11 | 12 | public bool triggered { get; set; default = false; } 13 | 14 | public int trigger_pressure_threshold { get; construct; } 15 | public int release_pressure_threshold { get; construct; } 16 | public int retrigger_pressure_threshold { get; construct; } 17 | public int retrigger_delay { get; construct; } 18 | 19 | private Meta.Barrier barrier; 20 | 21 | private uint32 triggered_time; 22 | private double pressure; 23 | 24 | /** 25 | * @param trigger_pressure_threshold The amount of pixels to travel additionally for 26 | * the barrier to trigger. Set to 0 to immediately activate. 27 | * @param retrigger_pressure_threshold The amount of pixels to travel additionally for 28 | * the barrier to trigger again. Set to int.MAX to disallow retrigger. 29 | */ 30 | public Barrier ( 31 | Meta.Backend backend, 32 | int x1, 33 | int y1, 34 | int x2, 35 | int y2, 36 | Meta.BarrierDirection directions, 37 | int trigger_pressure_threshold, 38 | int release_pressure_threshold, 39 | int retrigger_pressure_threshold, 40 | int retrigger_delay 41 | ) { 42 | Object ( 43 | trigger_pressure_threshold: trigger_pressure_threshold, 44 | release_pressure_threshold: release_pressure_threshold, 45 | retrigger_pressure_threshold: retrigger_pressure_threshold, 46 | retrigger_delay: retrigger_delay 47 | ); 48 | 49 | try { 50 | barrier = new Meta.Barrier (backend, x1, y1, x2, y2, directions, Meta.BarrierFlags.NONE); 51 | barrier.hit.connect (on_hit); 52 | barrier.left.connect (on_left); 53 | } catch (Error e) { 54 | warning ("Failed to create Meta Barrier"); 55 | } 56 | } 57 | 58 | ~Barrier () { 59 | barrier.destroy (); 60 | } 61 | 62 | private void on_hit (Meta.BarrierEvent event) { 63 | if (POSITIVE_X in barrier.directions || NEGATIVE_X in barrier.directions) { 64 | pressure += event.dx.abs (); 65 | } else { 66 | pressure += event.dy.abs (); 67 | } 68 | 69 | if (!triggered && pressure > trigger_pressure_threshold) { 70 | emit_trigger (event.time); 71 | } 72 | 73 | if (!triggered && pressure > release_pressure_threshold) { 74 | barrier.release (event); 75 | } 76 | 77 | if (triggered && pressure.abs () > retrigger_pressure_threshold && event.time > retrigger_delay + triggered_time) { 78 | emit_trigger (event.time); 79 | } 80 | } 81 | 82 | private void emit_trigger (uint32 time) { 83 | triggered = true; 84 | pressure = 0; 85 | triggered_time = time; 86 | 87 | trigger (); 88 | } 89 | 90 | private void on_left () { 91 | pressure = 0; 92 | triggered = false; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/KeyboardManager.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Santiago León 3 | * Copyright 2023-2025 elementary, Inc. 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | */ 6 | 7 | public class Gala.KeyboardManager : Object { 8 | private const string[] BLOCKED_OPTIONS = { 9 | "grp:alt_caps_toggle", "grp:alt_shift_toggle", "grp:alt_space_toggle", 10 | "grp:shifts_toggle", "grp:caps_toggle", "grp:ctrl_alt_toggle", 11 | "grp:ctrl_shift_toggle", "grp:shift_caps_toggle" 12 | }; 13 | 14 | public Meta.Display display { construct; private get; } 15 | 16 | private GLib.Settings settings; 17 | 18 | public KeyboardManager (Meta.Display display) { 19 | Object (display: display); 20 | } 21 | 22 | construct { 23 | settings = new GLib.Settings ("org.gnome.desktop.input-sources"); 24 | 25 | on_settings_changed ("sources"); // Update the list of layouts 26 | on_settings_changed ("current"); // Set current layout 27 | 28 | settings.changed.connect (on_settings_changed); 29 | 30 | display.modifiers_accelerator_activated.connect (() => switch_input_source (false)); 31 | 32 | var keybinding_settings = new GLib.Settings ("io.elementary.desktop.wm.keybindings"); 33 | display.add_keybinding ("switch-input-source", keybinding_settings, IGNORE_AUTOREPEAT, handle_keybinding); 34 | display.add_keybinding ("switch-input-source-backward", keybinding_settings, IGNORE_AUTOREPEAT, handle_keybinding); 35 | } 36 | 37 | private void handle_keybinding ( 38 | Meta.Display display, Meta.Window? window, Clutter.KeyEvent? event, Meta.KeyBinding binding 39 | ) { 40 | switch_input_source (binding.get_name ().has_suffix ("-backward")); 41 | } 42 | 43 | private bool switch_input_source (bool backward) { 44 | #if HAS_MUTTER46 45 | display.get_compositor ().backend.ungrab_keyboard (display.get_current_time ()); 46 | #else 47 | display.ungrab_keyboard (display.get_current_time ()); 48 | #endif 49 | 50 | var sources = settings.get_value ("sources"); 51 | 52 | var n_sources = (uint) sources.n_children (); 53 | if (n_sources < 2) { 54 | return true; 55 | } 56 | 57 | var current = settings.get_uint ("current"); 58 | 59 | if (!backward) { 60 | settings.set_uint ("current", (current + 1) % n_sources); 61 | } else { 62 | settings.set_uint ("current", (current - 1) % n_sources); 63 | } 64 | 65 | return true; 66 | } 67 | 68 | private void on_settings_changed (string key) { 69 | unowned var backend = display.get_context ().get_backend (); 70 | 71 | if (key == "sources" || key == "xkb-options" || key == "xkb-model") { 72 | string[] layouts = {}, variants = {}; 73 | 74 | var sources = settings.get_value ("sources"); 75 | for (int i = 0; i < sources.n_children (); i++) { 76 | unowned string? type = null, name = null; 77 | sources.get_child (i, "(&s&s)", out type, out name); 78 | 79 | if (type == "xkb") { 80 | string[] arr = name.split ("+", 2); 81 | layouts += arr[0]; 82 | variants += arr[1] ?? ""; 83 | 84 | } 85 | } 86 | 87 | if (layouts.length == 0) { 88 | layouts = { "us" }; 89 | variants = { "" }; 90 | } 91 | 92 | string[] xkb_options = {}; 93 | if (layouts.length == 1) { 94 | foreach (unowned var option in settings.get_strv ("xkb-options")) { 95 | if (!(option in BLOCKED_OPTIONS)) { 96 | xkb_options += option; 97 | } 98 | } 99 | } else { 100 | xkb_options = settings.get_strv ("xkb-options"); 101 | } 102 | 103 | var layout = string.joinv (",", layouts); 104 | var variant = string.joinv (",", variants); 105 | var options = string.joinv (",", xkb_options); 106 | 107 | #if HAS_MUTTER46 108 | backend.set_keymap (layout, variant, options, settings.get_string ("xkb-model")); 109 | #else 110 | backend.set_keymap (layout, variant, options); 111 | #endif 112 | } else if (key == "current") { 113 | backend.lock_layout_group (settings.get_uint ("current")); 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/Main.vala: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2012 Tom Beckmann, Rico Tzschichholz 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program 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 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | // 17 | 18 | namespace Gala { 19 | private const OptionEntry[] OPTIONS = { 20 | { "version", 0, OptionFlags.NO_ARG, OptionArg.CALLBACK, (void*) print_version, "Print version", null }, 21 | { null } 22 | }; 23 | 24 | private void print_version () { 25 | stdout.printf ("Gala %s\n", Config.VERSION); 26 | Meta.exit (Meta.ExitCode.SUCCESS); 27 | } 28 | 29 | public static int main (string[] args) { 30 | GLib.Intl.setlocale (LocaleCategory.ALL, ""); 31 | GLib.Intl.bindtextdomain (Config.GETTEXT_PACKAGE, Config.LOCALEDIR); 32 | GLib.Intl.bind_textdomain_codeset (Config.GETTEXT_PACKAGE, "UTF-8"); 33 | GLib.Intl.textdomain (Config.GETTEXT_PACKAGE); 34 | 35 | var ctx = new Meta.Context ("Mutter(Gala)"); 36 | ctx.add_option_entries (Gala.OPTIONS, Config.GETTEXT_PACKAGE); 37 | try { 38 | ctx.configure (ref args); 39 | } catch (Error e) { 40 | stderr.printf ("Error initializing: %s\n", e.message); 41 | return Posix.EXIT_FAILURE; 42 | } 43 | 44 | /* Intercept signals */ 45 | ctx.set_plugin_gtype (typeof (WindowManagerGala)); 46 | Posix.sigset_t empty_mask; 47 | Posix.sigemptyset (out empty_mask); 48 | Posix.sigaction_t act = {}; 49 | act.sa_handler = Posix.SIG_IGN; 50 | act.sa_mask = empty_mask; 51 | act.sa_flags = 0; 52 | 53 | if (Posix.sigaction (Posix.Signal.PIPE, act, null) < 0) { 54 | warning ("Failed to register SIGPIPE handler: %s", GLib.strerror (GLib.errno)); 55 | } 56 | 57 | if (Posix.sigaction (Posix.Signal.XFSZ, act, null) < 0) { 58 | warning ("Failed to register SIGXFSZ handler: %s", GLib.strerror (GLib.errno)); 59 | } 60 | 61 | GLib.Unix.signal_add (Posix.Signal.TERM, () => { 62 | ctx.terminate (); 63 | return GLib.Source.REMOVE; 64 | }); 65 | 66 | try { 67 | ctx.setup (); 68 | } catch (Error e) { 69 | stderr.printf ("Failed to setup: %s\n", e.message); 70 | return Posix.EXIT_FAILURE; 71 | } 72 | 73 | // Force initialization of static fields in Utils class 74 | // https://gitlab.gnome.org/GNOME/vala/-/issues/11 75 | typeof (Gala.Utils).class_ref (); 76 | 77 | try { 78 | ctx.start (); 79 | if (ctx.get_compositor_type () == Meta.CompositorType.WAYLAND) { 80 | Gala.init_pantheon_shell (ctx); 81 | } 82 | } catch (Error e) { 83 | stderr.printf ("Failed to start: %s\n", e.message); 84 | return Posix.EXIT_FAILURE; 85 | } 86 | 87 | try { 88 | ctx.run_main_loop (); 89 | } catch (Error e) { 90 | stderr.printf ("Gala terminated with a failure: %s\n", e.message); 91 | return Posix.EXIT_FAILURE; 92 | } 93 | 94 | WindowStateSaver.on_shutdown (); 95 | 96 | return Posix.EXIT_SUCCESS; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/NotificationsManager.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2016 Rico Tzschichholz 4 | * 2025 elementary, Inc. (https://elementary.io) 5 | */ 6 | 7 | /** 8 | * Gala.NotificationsManager can be used to send notifications to org.freedesktop.Notifications 9 | */ 10 | public class Gala.NotificationsManager : GLib.Object { 11 | [DBus (name = "org.freedesktop.Notifications")] 12 | private interface DBusNotifications : GLib.Object { 13 | public signal void action_invoked (uint32 id, string action_key); 14 | 15 | public abstract async uint32 notify (string app_name, uint32 replaces_id, string app_icon, string summary, 16 | string body, string[] actions, HashTable hints, int32 expire_timeout) throws DBusError, IOError; 17 | } 18 | 19 | private const int EXPIRE_TIMEOUT = 2000; 20 | 21 | private GLib.SimpleActionGroup action_group = new GLib.SimpleActionGroup (); 22 | private DBusNotifications? notifications = null; 23 | private GLib.HashTable replaces_id_table = new GLib.HashTable (str_hash, str_equal); 24 | 25 | construct { 26 | Bus.watch_name (BusType.SESSION, "org.freedesktop.Notifications", BusNameWatcherFlags.NONE, on_watch, on_unwatch); 27 | } 28 | 29 | private void on_watch (DBusConnection connection) { 30 | connection.get_proxy.begin ( 31 | "org.freedesktop.Notifications", "/org/freedesktop/Notifications", DBusProxyFlags.NONE, null, 32 | (obj, res) => { 33 | try { 34 | notifications = ((DBusConnection) obj).get_proxy.end (res); 35 | notifications.action_invoked.connect (handle_action_invoked); 36 | } catch (Error e) { 37 | warning ("NotificationsManager: Couldn't connect to notifications server: %s", e.message); 38 | notifications = null; 39 | } 40 | } 41 | ); 42 | } 43 | 44 | private void on_unwatch (DBusConnection conn) { 45 | warning ("NotificationsManager: Lost connection to notifications server"); 46 | notifications = null; 47 | } 48 | 49 | private void handle_action_invoked (uint32 id, string action_name) { 50 | string name; 51 | GLib.Variant? target_value; 52 | 53 | try { 54 | GLib.Action.parse_detailed_name (action_name, out name, out target_value); 55 | } catch (Error e) { 56 | warning ("NotificationsManager: Couldn't parse action: %s", e.message); 57 | return; 58 | } 59 | 60 | if (action_group.has_action (name)) { 61 | action_group.activate_action (name, target_value); 62 | } 63 | } 64 | 65 | public void add_action (GLib.Action action) { 66 | action_group.add_action (action); 67 | } 68 | 69 | public async void send ( 70 | string component_name, 71 | string icon, 72 | string summary, 73 | string body, 74 | string[] actions, 75 | GLib.HashTable hints 76 | ) { 77 | if (notifications == null) { 78 | warning ("NotificationsManager: Unable to send notification. No connection to notification server"); 79 | return; 80 | } 81 | 82 | uint32? replaces_id = replaces_id_table.get (component_name); 83 | if (replaces_id == null) { 84 | replaces_id = 0; 85 | } 86 | 87 | try { 88 | var notification_id = yield notifications.notify ( 89 | "gala-feedback", 90 | replaces_id, 91 | icon, 92 | summary, 93 | body, 94 | actions, 95 | hints, 96 | EXPIRE_TIMEOUT 97 | ); 98 | 99 | replaces_id_table.insert (component_name, notification_id); 100 | } catch (Error e) { 101 | critical ("NotificationsManager: There was an error sending a notification: %s", e.message); 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/ScreenSaverManager.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2020, 2025 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | [DBus (name="org.gnome.ScreenSaver")] 7 | public class Gala.ScreenSaverManager : Object { 8 | public signal void active_changed (bool new_value); 9 | 10 | [DBus (visible = false)] 11 | public SessionLocker session_locker { get; construct; } 12 | 13 | public ScreenSaverManager (SessionLocker session_locker) { 14 | Object (session_locker: session_locker); 15 | } 16 | 17 | construct { 18 | session_locker.active_changed.connect (() => { 19 | active_changed (session_locker.active); 20 | }); 21 | } 22 | 23 | public void @lock () throws GLib.Error { 24 | session_locker.@lock (true); 25 | } 26 | 27 | public bool get_active () throws GLib.Error { 28 | return session_locker.active; 29 | } 30 | 31 | public void set_active (bool active) throws GLib.Error { 32 | if (active) { 33 | session_locker.activate (true); 34 | } else { 35 | session_locker.deactivate (false); 36 | } 37 | } 38 | 39 | public uint get_active_time () throws GLib.Error { 40 | var started = session_locker.activation_time; 41 | if (started > 0) { 42 | return (uint)Math.floor ((GLib.get_monotonic_time () - started) / 1000000); 43 | } else { 44 | return 0; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/SessionManager.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2018 Adam Bieńkowski 4 | * 2025 elementary, Inc. (https://elementary.io) 5 | */ 6 | 7 | // Reference code by the Solus Project: 8 | // https://github.com/solus-project/budgie-desktop/blob/master/src/wm/shim.vala 9 | 10 | [DBus (name = "org.gnome.SessionManager.EndSessionDialog")] 11 | public class Gala.SessionManager : Object { 12 | [DBus (name = "io.elementary.wingpanel.session.EndSessionDialog")] 13 | private interface WingpanelEndSessionDialog : Object { 14 | public signal void confirmed_logout (); 15 | public signal void confirmed_reboot (); 16 | public signal void confirmed_shutdown (); 17 | public signal void canceled (); 18 | public signal void closed (); 19 | 20 | public abstract void open (uint type, uint timestamp, uint open_length, ObjectPath[] inhibiters) throws DBusError, IOError; 21 | } 22 | 23 | private static SessionManager? instance; 24 | 25 | [DBus (visible = false)] 26 | public static unowned SessionManager init () { 27 | if (instance == null) { 28 | instance = new SessionManager (); 29 | } 30 | 31 | return instance; 32 | } 33 | 34 | public signal void confirmed_logout (); 35 | public signal void confirmed_reboot (); 36 | public signal void confirmed_shutdown (); 37 | public signal void canceled (); 38 | public signal void closed (); 39 | 40 | private WingpanelEndSessionDialog? proxy = null; 41 | 42 | private SessionManager () { 43 | Bus.watch_name (BusType.SESSION, "io.elementary.wingpanel.session.EndSessionDialog", 44 | BusNameWatcherFlags.NONE, proxy_appeared, proxy_vanished); 45 | } 46 | 47 | private void get_proxy_cb (Object? o, AsyncResult? res) { 48 | try { 49 | proxy = Bus.get_proxy.end (res); 50 | } catch (Error e) { 51 | warning ("Could not connect to io.elementary.wingpanel.session.EndSessionDialog proxy: %s", e.message); 52 | return; 53 | } 54 | 55 | proxy.confirmed_logout.connect (() => confirmed_logout ()); 56 | proxy.confirmed_reboot.connect (() => confirmed_reboot ()); 57 | proxy.confirmed_shutdown.connect (() => confirmed_shutdown ()); 58 | proxy.canceled.connect (() => canceled ()); 59 | proxy.closed.connect (() => closed ()); 60 | } 61 | 62 | private void proxy_appeared () { 63 | Bus.get_proxy.begin (BusType.SESSION, 64 | "io.elementary.wingpanel.session.EndSessionDialog", "/io/elementary/wingpanel/session/EndSessionDialog", 65 | 0, null, get_proxy_cb); 66 | } 67 | 68 | private void proxy_vanished () { 69 | proxy = null; 70 | } 71 | 72 | public void open (uint type, uint timestamp, uint open_length, ObjectPath[] inhibiters) throws DBusError, IOError { 73 | if (proxy == null) { 74 | throw new DBusError.FAILED ("io.elementary.wingpanel.session.EndSessionDialog DBus interface is not registered."); 75 | } 76 | 77 | proxy.open (type, timestamp, open_length, inhibiters); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/ShellClients/ManagedClient.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 elementary, Inc. (https://elementary.io) 3 | * SPDX-License-Identifier: GPL-3.0-or-later 4 | * 5 | * Authored by: Leonhard Kargl 6 | */ 7 | 8 | /** 9 | * Utility class that takes care of launching and restarting a subprocess. 10 | * On wayland this uses a WaylandClient and emits window_created if a window for the client was created. 11 | * On X this just launches a normal subprocess and never emits window_created. 12 | */ 13 | public class Gala.ManagedClient : Object { 14 | public signal void window_created (Meta.Window window); 15 | 16 | public Meta.Display display { get; construct; } 17 | public string[] args { get; construct; } 18 | 19 | public Meta.WaylandClient? wayland_client { get; private set; } 20 | 21 | private Subprocess? subprocess; 22 | 23 | public ManagedClient (Meta.Display display, string[] args) { 24 | Object (display: display, args: args); 25 | } 26 | 27 | construct { 28 | if (Meta.Util.is_wayland_compositor ()) { 29 | start_wayland.begin (); 30 | 31 | display.window_created.connect ((window) => { 32 | if (wayland_client != null && wayland_client.owns_window (window)) { 33 | window_created (window); 34 | 35 | // We have to manage is alive manually since windows created by WaylandClients have our pid 36 | // and we don't want to end our own process 37 | window.notify["is-alive"].connect (() => { 38 | if (!window.is_alive && subprocess != null) { 39 | subprocess.force_exit (); 40 | warning ("WaylandClient window became unresponsive, killing the client."); 41 | } 42 | }); 43 | } 44 | }); 45 | } else { 46 | start_x.begin (); 47 | } 48 | } 49 | 50 | private async void start_wayland () { 51 | var subprocess_launcher = new GLib.SubprocessLauncher (INHERIT_FDS); 52 | try { 53 | wayland_client = new Meta.WaylandClient (display.get_context (), subprocess_launcher); 54 | subprocess = wayland_client.spawnv (display, args); 55 | 56 | yield subprocess.wait_async (); 57 | 58 | //Restart the daemon if it crashes 59 | Timeout.add_seconds (1, () => { 60 | start_wayland.begin (); 61 | return Source.REMOVE; 62 | }); 63 | } catch (Error e) { 64 | warning ("Failed to create dock client: %s", e.message); 65 | return; 66 | } 67 | } 68 | 69 | private async void start_x () { 70 | try { 71 | subprocess = new Subprocess.newv (args, NONE); 72 | yield subprocess.wait_async (); 73 | 74 | //Restart the daemon if it crashes 75 | Timeout.add_seconds (1, () => { 76 | start_x.begin (); 77 | return Source.REMOVE; 78 | }); 79 | } catch (Error e) { 80 | warning ("Failed to create daemon subprocess with x: %s", e.message); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/ShellClients/NotificationsClient.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 elementary, Inc. (https://elementary.io) 3 | * SPDX-License-Identifier: GPL-3.0-or-later 4 | * 5 | * Authored by: Leonhard Kargl 6 | */ 7 | 8 | public class Gala.NotificationsClient : Object { 9 | public Meta.Display display { get; construct; } 10 | 11 | private ManagedClient client; 12 | 13 | public NotificationsClient (Meta.Display display) { 14 | Object (display: display); 15 | } 16 | 17 | construct { 18 | client = new ManagedClient (display, { "io.elementary.notifications" }); 19 | 20 | client.window_created.connect ((window) => { 21 | window.set_data (NOTIFICATION_DATA_KEY, true); 22 | window.make_above (); 23 | window.stick (); 24 | #if HAS_MUTTER46 25 | client.wayland_client.make_dock (window); 26 | #endif 27 | }); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/ShellClients/PositionedWindow.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 elementary, Inc. (https://elementary.io) 3 | * SPDX-License-Identifier: GPL-3.0-or-later 4 | * 5 | * Authored by: Leonhard Kargl 6 | */ 7 | 8 | public class Gala.PositionedWindow : Object { 9 | public enum Position { 10 | TOP, 11 | BOTTOM, 12 | CENTER; 13 | 14 | public static Position from_anchor (Pantheon.Desktop.Anchor anchor) { 15 | if (anchor > 1) { 16 | warning ("Position %s not supported yet", anchor.to_string ()); 17 | return CENTER; 18 | } 19 | 20 | return (Position) anchor; 21 | } 22 | } 23 | 24 | public Meta.Window window { get; construct; } 25 | /** 26 | * This may only be set after the window was shown. 27 | * The initial position should only be given in the constructor. 28 | */ 29 | public Position position { get; construct set; } 30 | public Variant? position_data { get; construct set; } 31 | 32 | private ulong position_changed_id; 33 | 34 | public PositionedWindow (Meta.Window window, Position position, Variant? position_data = null) { 35 | Object (window: window, position: position, position_data: position_data); 36 | } 37 | 38 | construct { 39 | window.stick (); 40 | 41 | window.size_changed.connect (position_window); 42 | position_changed_id = window.position_changed.connect (position_window); 43 | window.shown.connect (position_window); 44 | 45 | unowned var monitor_manager = window.display.get_context ().get_backend ().get_monitor_manager (); 46 | monitor_manager.monitors_changed.connect (position_window); 47 | monitor_manager.monitors_changed_internal.connect (position_window); 48 | 49 | notify["position"].connect (position_window); 50 | notify["position-data"].connect (position_window); 51 | } 52 | 53 | private void position_window () { 54 | int x = 0, y = 0; 55 | var window_rect = window.get_frame_rect (); 56 | unowned var display = window.display; 57 | 58 | switch (position) { 59 | case CENTER: 60 | var monitor_geom = display.get_monitor_geometry (display.get_primary_monitor ()); 61 | x = monitor_geom.x + (monitor_geom.width - window_rect.width) / 2; 62 | y = monitor_geom.y + (monitor_geom.height - window_rect.height) / 2; 63 | break; 64 | 65 | case TOP: 66 | var monitor_geom = display.get_monitor_geometry (display.get_primary_monitor ()); 67 | x = monitor_geom.x + (monitor_geom.width - window_rect.width) / 2; 68 | y = monitor_geom.y; 69 | break; 70 | 71 | case BOTTOM: 72 | var monitor_geom = display.get_monitor_geometry (display.get_primary_monitor ()); 73 | x = monitor_geom.x + (monitor_geom.width - window_rect.width) / 2; 74 | y = monitor_geom.y + monitor_geom.height - window_rect.height; 75 | break; 76 | } 77 | 78 | SignalHandler.block (window, position_changed_id); 79 | window.move_frame (false, x, y); 80 | SignalHandler.unblock (window, position_changed_id); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/SuperScrollAction.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2024 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | public class Gala.SuperScrollAction : Clutter.Action { 7 | public signal bool triggered (uint32 timestamp, double dx, double dy); 8 | 9 | public Meta.Display display { private get; construct; } 10 | 11 | public SuperScrollAction (Meta.Display display) { 12 | Object (display: display); 13 | } 14 | 15 | public override bool handle_event (Clutter.Event event) { 16 | if ( 17 | event.get_type () == SCROLL && 18 | (event.get_state () & display.compositor_modifiers) != 0 19 | ) { 20 | double dx = 0.0, dy = 0.0; 21 | switch (event.get_scroll_direction ()) { 22 | case LEFT: 23 | dx = -1.0; 24 | break; 25 | case RIGHT: 26 | dx = 1.0; 27 | break; 28 | case UP: 29 | dy = 1.0; 30 | break; 31 | case DOWN: 32 | dy = -1.0; 33 | break; 34 | default: 35 | break; 36 | } 37 | 38 | // TODO: support natural scroll settings 39 | 40 | return triggered (event.get_time (), dx, dy); 41 | } 42 | 43 | return Clutter.EVENT_PROPAGATE; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Widgets/MultitaskingView/MonitorClone.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2014 Tom Beckmann 4 | * 2025 elementary, Inc. (https://elementary.io) 5 | */ 6 | 7 | /** 8 | * More or less utility class to contain a WindowCloneContainer for each 9 | * non-primary monitor. It's the pendant to the WorkspaceClone which is 10 | * only placed on the primary monitor. It also draws a wallpaper behind itself 11 | * as the WindowGroup is hidden while the view is active. Only used when 12 | * workspaces-only-on-primary is set to true. 13 | */ 14 | public class Gala.MonitorClone : ActorTarget { 15 | public signal void window_selected (Meta.Window window); 16 | 17 | public WindowManager wm { get; construct; } 18 | public int monitor { get; construct; } 19 | public float monitor_scale { get; construct set; } 20 | 21 | private WindowCloneContainer window_container; 22 | private BackgroundManager background; 23 | 24 | public MonitorClone (WindowManager wm, int monitor) { 25 | Object (wm: wm, monitor: monitor); 26 | } 27 | 28 | construct { 29 | reactive = true; 30 | update_allocation (); 31 | 32 | unowned var display = wm.get_display (); 33 | 34 | background = new BackgroundManager (display, monitor, false); 35 | 36 | window_container = new WindowCloneContainer (wm, monitor_scale); 37 | window_container.add_constraint (new Clutter.BindConstraint (this, SIZE, 0.0f)); 38 | window_container.window_selected.connect ((w) => { window_selected (w); }); 39 | bind_property ("monitor-scale", window_container, "monitor-scale"); 40 | 41 | display.window_entered_monitor.connect (window_entered); 42 | display.window_left_monitor.connect (window_left); 43 | 44 | unowned GLib.List window_actors = display.get_window_actors (); 45 | foreach (unowned Meta.WindowActor window_actor in window_actors) { 46 | if (window_actor.is_destroyed ()) 47 | continue; 48 | 49 | unowned Meta.Window window = window_actor.get_meta_window (); 50 | if (window.get_monitor () == monitor) { 51 | window_entered (monitor, window); 52 | } 53 | } 54 | 55 | add_child (background); 56 | add_child (window_container); 57 | 58 | var drop = new DragDropAction (DragDropActionType.DESTINATION, "multitaskingview-window"); 59 | add_action (drop); 60 | } 61 | 62 | ~MonitorClone () { 63 | unowned var display = wm.get_display (); 64 | display.window_entered_monitor.disconnect (window_entered); 65 | display.window_left_monitor.disconnect (window_left); 66 | } 67 | 68 | /** 69 | * Make sure the MonitorClone is at the location of the monitor on the stage 70 | */ 71 | public void update_allocation () { 72 | unowned var display = wm.get_display (); 73 | 74 | var monitor_geometry = display.get_monitor_geometry (monitor); 75 | 76 | set_position (monitor_geometry.x, monitor_geometry.y); 77 | set_size (monitor_geometry.width, monitor_geometry.height); 78 | 79 | monitor_scale = display.get_monitor_scale (monitor); 80 | } 81 | 82 | private void window_left (int window_monitor, Meta.Window window) { 83 | if (window_monitor != monitor) 84 | return; 85 | 86 | window_container.remove_window (window); 87 | } 88 | 89 | private void window_entered (int window_monitor, Meta.Window window) { 90 | if (window_monitor != monitor || window.window_type != Meta.WindowType.NORMAL) 91 | return; 92 | 93 | window_container.add_window (window); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/Widgets/MultitaskingView/StaticWindowClone.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 elementary, Inc. (https://elementary.io) 3 | * SPDX-License-Identifier: GPL-3.0-or-later 4 | * 5 | * Authored by: Leonhard Kargl 6 | */ 7 | 8 | /** 9 | * A exact clone of a window (same position and size). This is used for static 10 | * windows (e.g. on all workspaces or moving) and fades out while the multitasking view 11 | * is being opened. 12 | */ 13 | public class Gala.StaticWindowClone : ActorTarget { 14 | public Meta.Window window { get; construct; } 15 | 16 | public StaticWindowClone (Meta.Window window) { 17 | Object (window: window); 18 | } 19 | 20 | construct { 21 | var window_actor = (Meta.WindowActor) window.get_compositor_private (); 22 | var clone = new Clutter.Clone (window_actor); 23 | add_child (clone); 24 | 25 | add_target (new PropertyTarget (MULTITASKING_VIEW, this, "opacity", typeof (uint), 255u, 0u)); 26 | 27 | window_actor.bind_property ("x", this, "x", SYNC_CREATE); 28 | window_actor.bind_property ("y", this, "y", SYNC_CREATE); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Widgets/MultitaskingView/StaticWindowContainer.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2024 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | /** 7 | * Holds clones of static windows (e.g. on all workspaces or being moved) 8 | * in the multitasking view and fades them out while opening the multitasking view. 9 | * The window container use this to know whether a window became static (they shouldn't show it anymore) 10 | * or isn't static anymore (they have to show it now). 11 | */ 12 | public class Gala.StaticWindowContainer : ActorTarget { 13 | private static GLib.Once instance; 14 | public static StaticWindowContainer get_instance (Meta.Display display) { 15 | return instance.once (() => { return new StaticWindowContainer (display); }); 16 | } 17 | 18 | public signal void window_changed (Meta.Window window, bool is_static); 19 | 20 | public Meta.Display display { get; construct; } 21 | 22 | public Meta.Window? grabbed_window { get; private set; } 23 | public Meta.Window? moving_window { get; private set; } 24 | 25 | private StaticWindowContainer (Meta.Display display) { 26 | Object (display: display); 27 | } 28 | 29 | construct { 30 | display.grab_op_begin.connect (on_grab_op_begin); 31 | display.grab_op_end.connect (on_grab_op_end); 32 | 33 | WindowListener.get_default ().window_on_all_workspaces_changed.connect (on_all_workspaces_changed); 34 | } 35 | 36 | private void on_grab_op_begin (Meta.Window window, Meta.GrabOp op) { 37 | if (op != MOVING) { 38 | return; 39 | } 40 | 41 | grabbed_window = window; 42 | check_window_changed (window); 43 | } 44 | 45 | private void on_grab_op_end (Meta.Window window, Meta.GrabOp op) { 46 | grabbed_window = null; 47 | check_window_changed (window); 48 | } 49 | 50 | private void on_all_workspaces_changed (Meta.Window window) { 51 | // We have to wait for shell clients here 52 | Idle.add (() => { 53 | check_window_changed (window); 54 | return Source.REMOVE; 55 | }); 56 | } 57 | 58 | public void notify_window_moving (Meta.Window window) { 59 | moving_window = window; 60 | check_window_changed (window); 61 | } 62 | 63 | public void notify_move_ended () { 64 | if (moving_window == null) { 65 | return; 66 | } 67 | 68 | var window = moving_window; 69 | moving_window = null; 70 | check_window_changed (window); 71 | } 72 | 73 | private void check_window_changed (Meta.Window window) { 74 | var is_static = is_static (window) && !ShellClientsManager.get_instance ().is_positioned_window (window); 75 | 76 | Clutter.Actor? clone = null; 77 | for (var child = get_first_child (); child != null; child = child.get_next_sibling ()) { 78 | if (((StaticWindowClone) child).window == window) { 79 | clone = child; 80 | break; 81 | } 82 | } 83 | 84 | if (!is_static && clone != null) { 85 | remove_child (clone); 86 | } else if (is_static && !window.on_all_workspaces && clone == null) { 87 | add_child (new StaticWindowClone (window)); 88 | } 89 | 90 | window_changed (window, is_static); 91 | } 92 | 93 | public bool is_static (Meta.Window window) { 94 | return window == grabbed_window || window == moving_window || window.on_all_workspaces; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/Widgets/MultitaskingView/Tooltip.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 José Expósito 3 | * Copyright 2021-2023 elementary, Inc. 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | */ 6 | 7 | /** 8 | * Clutter actor to display text in a tooltip-like component. 9 | */ 10 | public class Gala.Tooltip : CanvasActor { 11 | /** 12 | * Actor to display the Tooltip text. 13 | */ 14 | private Clutter.Text text_actor; 15 | 16 | construct { 17 | #if HAS_MUTTER47 18 | Cogl.Color text_color = { 19 | #else 20 | Clutter.Color text_color = { 21 | #endif 22 | (uint8) Drawing.Color.TOOLTIP_TEXT_COLOR.red * uint8.MAX, 23 | (uint8) Drawing.Color.TOOLTIP_TEXT_COLOR.green * uint8.MAX, 24 | (uint8) Drawing.Color.TOOLTIP_TEXT_COLOR.blue * uint8.MAX, 25 | (uint8) Drawing.Color.TOOLTIP_TEXT_COLOR.alpha * uint8.MAX, 26 | }; 27 | 28 | text_actor = new Clutter.Text () { 29 | margin_left = 6, 30 | margin_top = 6, 31 | margin_bottom = 6, 32 | margin_right = 6, 33 | ellipsize = Pango.EllipsizeMode.MIDDLE, 34 | color = text_color 35 | }; 36 | 37 | add_child (text_actor); 38 | 39 | layout_manager = new Clutter.BinLayout (); 40 | } 41 | 42 | public void set_text (string new_text) { 43 | text_actor.text = new_text; 44 | } 45 | 46 | protected override void draw (Cairo.Context ctx, int width, int height) { 47 | ctx.save (); 48 | ctx.set_operator (Cairo.Operator.CLEAR); 49 | ctx.paint (); 50 | ctx.clip (); 51 | ctx.reset_clip (); 52 | ctx.set_operator (Cairo.Operator.OVER); 53 | 54 | var background_color = Drawing.Color.TOOLTIP_BACKGROUND; 55 | ctx.set_source_rgba ( 56 | background_color.red, 57 | background_color.green, 58 | background_color.blue, 59 | background_color.alpha 60 | ); 61 | 62 | Drawing.Utilities.cairo_rounded_rectangle (ctx, 0, 0, width, height, 4); 63 | ctx.fill (); 64 | 65 | ctx.restore (); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/Widgets/MultitaskingView/WorkspaceInsertThumb.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Tom Beckmann 3 | * Copyright 2023 elementary, Inc. (https://elementary.io) 4 | * SPDX-License-Identifier: GPL-3.0-or-later 5 | */ 6 | 7 | public class Gala.WorkspaceInsertThumb : Clutter.Actor { 8 | public const int EXPAND_DELAY = 300; 9 | 10 | public int workspace_index { get; construct set; } 11 | public bool expanded { get; set; default = false; } 12 | public int delay { get; set; default = EXPAND_DELAY; } 13 | private float _scale_factor = 1.0f; 14 | public float scale_factor { 15 | get { 16 | return _scale_factor; 17 | } 18 | set { 19 | if (value != _scale_factor) { 20 | _scale_factor = value; 21 | reallocate (); 22 | } 23 | } 24 | } 25 | 26 | private uint expand_timeout = 0; 27 | 28 | public WorkspaceInsertThumb (int workspace_index, float scale) { 29 | Object (workspace_index: workspace_index, scale_factor: scale); 30 | 31 | reallocate (); 32 | opacity = 0; 33 | set_pivot_point (0.5f, 0.5f); 34 | reactive = true; 35 | x_align = Clutter.ActorAlign.CENTER; 36 | 37 | var drop = new DragDropAction (DragDropActionType.DESTINATION, "multitaskingview-window"); 38 | drop.crossed.connect ((target, hovered) => { 39 | if (!hovered) { 40 | if (expand_timeout != 0) { 41 | Source.remove (expand_timeout); 42 | expand_timeout = 0; 43 | } 44 | 45 | transform (false); 46 | } else { 47 | expand_timeout = Timeout.add (delay, expand); 48 | } 49 | }); 50 | 51 | add_action (drop); 52 | } 53 | 54 | private void reallocate () { 55 | width = Utils.scale_to_int (IconGroupContainer.SPACING, scale_factor); 56 | height = Utils.scale_to_int (IconGroupContainer.GROUP_WIDTH, scale_factor); 57 | y = Utils.scale_to_int (IconGroupContainer.GROUP_WIDTH - IconGroupContainer.SPACING, scale_factor) / 2; 58 | } 59 | 60 | public void set_window_thumb (Meta.Window window) { 61 | destroy_all_children (); 62 | 63 | var icon = new WindowIcon (window, IconGroupContainer.GROUP_WIDTH, (int)Math.round (scale_factor)) { 64 | x = IconGroupContainer.SPACING, 65 | x_align = Clutter.ActorAlign.CENTER 66 | }; 67 | add_child (icon); 68 | } 69 | 70 | private bool expand () { 71 | expand_timeout = 0; 72 | 73 | transform (true); 74 | 75 | return Source.REMOVE; 76 | } 77 | 78 | private new void transform (bool expand) { 79 | save_easing_state (); 80 | set_easing_mode (Clutter.AnimationMode.EASE_OUT_QUAD); 81 | set_easing_duration (Utils.get_animation_duration (200)); 82 | 83 | if (!expand) { 84 | remove_transition ("pulse"); 85 | opacity = 0; 86 | width = Utils.scale_to_int (IconGroupContainer.SPACING, scale_factor); 87 | expanded = false; 88 | } else { 89 | add_pulse_animation (); 90 | opacity = 200; 91 | width = Utils.scale_to_int (IconGroupContainer.GROUP_WIDTH + IconGroupContainer.SPACING * 2, scale_factor); 92 | expanded = true; 93 | } 94 | 95 | restore_easing_state (); 96 | } 97 | 98 | private void add_pulse_animation () { 99 | if (!Meta.Prefs.get_gnome_animations ()) { 100 | return; 101 | } 102 | 103 | var transition = new Clutter.TransitionGroup () { 104 | duration = 800, 105 | auto_reverse = true, 106 | repeat_count = -1, 107 | progress_mode = Clutter.AnimationMode.LINEAR 108 | }; 109 | 110 | var scale_x_transition = new Clutter.PropertyTransition ("scale-x"); 111 | scale_x_transition.set_from_value (0.8); 112 | scale_x_transition.set_to_value (1.1); 113 | scale_x_transition.auto_reverse = true; 114 | 115 | var scale_y_transition = new Clutter.PropertyTransition ("scale-y"); 116 | scale_y_transition.set_from_value (0.8); 117 | scale_y_transition.set_to_value (1.1); 118 | scale_y_transition.auto_reverse = true; 119 | 120 | transition.add_transition (scale_x_transition); 121 | transition.add_transition (scale_y_transition); 122 | 123 | add_transition ("pulse", transition); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/Widgets/MultitaskingView/WorkspaceRow.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 elementary, Inc. (https://elementary.io) 3 | * SPDX-License-Identifier: GPL-3.0-or-later 4 | * 5 | * Authored by: Leonhard Kargl 6 | */ 7 | 8 | public class Gala.WorkspaceRow : ActorTarget { 9 | public const int WORKSPACE_GAP = 24; 10 | 11 | public Meta.Display display { get; construct; } 12 | 13 | public WorkspaceRow (Meta.Display display) { 14 | Object (display: display); 15 | } 16 | 17 | construct { 18 | unowned var manager = display.get_workspace_manager (); 19 | manager.workspaces_reordered.connect (update_order); 20 | } 21 | 22 | public override void allocate (Clutter.ActorBox allocation) { 23 | set_allocation (allocation); 24 | 25 | double progress = get_current_progress (SWITCH_WORKSPACE); 26 | int index = 0; 27 | for (var child = get_first_child (); child != null; child = child.get_next_sibling ()) { 28 | float preferred_width; 29 | child.get_preferred_width (-1, null, out preferred_width); 30 | 31 | var child_x = (float) Math.round ((progress + index) * (preferred_width + WORKSPACE_GAP)); 32 | 33 | child.allocate_preferred_size (child_x, 0); 34 | 35 | index++; 36 | } 37 | } 38 | 39 | public override void update_progress (GestureAction action, double to) { 40 | if (action == SWITCH_WORKSPACE) { 41 | queue_relayout (); 42 | } 43 | } 44 | 45 | private void update_order () { 46 | for (var child = get_first_child (); child != null; child = child.get_next_sibling ()) { 47 | unowned var workspace_clone = (WorkspaceClone) child; 48 | set_child_at_index (workspace_clone, workspace_clone.workspace.index ()); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Widgets/PixelPicker.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2020 elementary, Inc. (https://elementary.io) 4 | */ 5 | 6 | public class Gala.PixelPicker : Clutter.Actor { 7 | public signal void closed (); 8 | 9 | public WindowManager wm { get; construct; } 10 | public bool cancelled { get; private set; } 11 | public Graphene.Point point { get; private set; } 12 | 13 | private ModalProxy? modal_proxy; 14 | 15 | public PixelPicker (WindowManager wm) { 16 | Object (wm: wm); 17 | } 18 | 19 | construct { 20 | point.init (0, 0); 21 | visible = true; 22 | reactive = true; 23 | 24 | int screen_width, screen_height; 25 | wm.get_display ().get_size (out screen_width, out screen_height); 26 | width = screen_width; 27 | height = screen_height; 28 | } 29 | 30 | public override bool key_press_event (Clutter.Event e) { 31 | if (e.get_key_symbol () == Clutter.Key.Escape) { 32 | cancelled = true; 33 | close (); 34 | 35 | return true; 36 | } 37 | 38 | return false; 39 | } 40 | 41 | public override bool button_release_event (Clutter.Event e) { 42 | if (e.get_button () != Clutter.Button.PRIMARY) { 43 | return true; 44 | } 45 | 46 | float x, y; 47 | e.get_coords (out x, out y); 48 | point = Graphene.Point () { x = x, y = y }; 49 | 50 | hide (); 51 | close (); 52 | 53 | return true; 54 | } 55 | 56 | private void close () { 57 | wm.get_display ().set_cursor (Meta.Cursor.DEFAULT); 58 | if (modal_proxy != null) { 59 | wm.pop_modal (modal_proxy); 60 | } 61 | 62 | closed (); 63 | } 64 | 65 | public void start_selection () { 66 | wm.get_display ().set_cursor (Meta.Cursor.CROSSHAIR); 67 | grab_key_focus (); 68 | 69 | modal_proxy = wm.push_modal (this); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/Widgets/SelectionArea.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: GPL-3.0-or-later 3 | * SPDX-FileCopyrightText: 2017 Santiago León O. 4 | * 2017 Adam Bieńkowski 5 | * 2025 elementary, Inc. (https://elementary.io) 6 | */ 7 | 8 | public class Gala.SelectionArea : CanvasActor { 9 | public signal void closed (); 10 | 11 | public WindowManager wm { get; construct; } 12 | 13 | public bool cancelled { get; private set; } 14 | 15 | private ModalProxy? modal_proxy; 16 | private Graphene.Point start_point; 17 | private Graphene.Point end_point; 18 | private bool dragging = false; 19 | private bool clicked = false; 20 | 21 | public SelectionArea (WindowManager wm) { 22 | Object (wm: wm); 23 | } 24 | 25 | construct { 26 | start_point.init (0, 0); 27 | end_point.init (0, 0); 28 | visible = true; 29 | reactive = true; 30 | 31 | int screen_width, screen_height; 32 | wm.get_display ().get_size (out screen_width, out screen_height); 33 | width = screen_width; 34 | height = screen_height; 35 | } 36 | 37 | public override bool key_press_event (Clutter.Event e) { 38 | if (e.get_key_symbol () == Clutter.Key.Escape) { 39 | close (); 40 | cancelled = true; 41 | closed (); 42 | return true; 43 | } 44 | 45 | return false; 46 | } 47 | 48 | public override bool button_press_event (Clutter.Event e) { 49 | if (dragging || e.get_button () != Clutter.Button.PRIMARY) { 50 | return true; 51 | } 52 | 53 | clicked = true; 54 | 55 | float x, y; 56 | e.get_coords (out x, out y); 57 | start_point.init (x, y); 58 | 59 | return true; 60 | } 61 | 62 | public override bool button_release_event (Clutter.Event e) { 63 | if (e.get_button () != Clutter.Button.PRIMARY) { 64 | return true; 65 | } 66 | 67 | if (!dragging) { 68 | close (); 69 | cancelled = true; 70 | closed (); 71 | return true; 72 | } 73 | 74 | dragging = false; 75 | clicked = false; 76 | 77 | close (); 78 | this.hide (); 79 | content.invalidate (); 80 | 81 | closed (); 82 | return true; 83 | } 84 | 85 | public override bool motion_event (Clutter.Event e) { 86 | if (!clicked) { 87 | return true; 88 | } 89 | 90 | float x, y; 91 | e.get_coords (out x, out y); 92 | end_point.init (x, y); 93 | content.invalidate (); 94 | 95 | if (!dragging) { 96 | dragging = true; 97 | } 98 | 99 | return true; 100 | } 101 | 102 | public void close () { 103 | wm.get_display ().set_cursor (Meta.Cursor.DEFAULT); 104 | 105 | if (modal_proxy != null) { 106 | wm.pop_modal (modal_proxy); 107 | } 108 | } 109 | 110 | public void start_selection () { 111 | wm.get_display ().set_cursor (Meta.Cursor.CROSSHAIR); 112 | grab_key_focus (); 113 | 114 | modal_proxy = wm.push_modal (this); 115 | } 116 | 117 | public Graphene.Rect get_selection_rectangle () { 118 | return Graphene.Rect () { 119 | origin = start_point, 120 | size = Graphene.Size.zero () 121 | }.expand (end_point); 122 | } 123 | 124 | protected override void draw (Cairo.Context ctx, int width, int height) { 125 | ctx.save (); 126 | 127 | ctx.set_operator (Cairo.Operator.CLEAR); 128 | ctx.paint (); 129 | 130 | ctx.restore (); 131 | 132 | if (!dragging) { 133 | return; 134 | } 135 | 136 | ctx.translate (0.5, 0.5); 137 | 138 | var rect = get_selection_rectangle (); 139 | ctx.rectangle (rect.origin.x, rect.origin.y, rect.size.width, rect.size.height); 140 | ctx.set_source_rgba (0.1, 0.1, 0.1, 0.2); 141 | ctx.fill (); 142 | 143 | ctx.rectangle (rect.origin.x, rect.origin.y, rect.size.width, rect.size.height); 144 | ctx.set_source_rgb (0.7, 0.7, 0.7); 145 | ctx.set_line_width (1.0); 146 | ctx.stroke (); 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /src/Widgets/WindowSwitcher/WindowSwitcherIcon.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 elementary, Inc. 3 | * SPDX-License-Identifier: GPL-3.0-or-later 4 | */ 5 | 6 | public class Gala.WindowSwitcherIcon : CanvasActor { 7 | private const int WRAPPER_BORDER_RADIUS = 3; 8 | 9 | public Meta.Window window { get; construct; } 10 | 11 | private WindowIcon icon; 12 | 13 | private bool _selected = false; 14 | public bool selected { 15 | get { 16 | return _selected; 17 | } 18 | set { 19 | _selected = value; 20 | content.invalidate (); 21 | } 22 | } 23 | 24 | private float _scale_factor = 1.0f; 25 | public float scale_factor { 26 | get { 27 | return _scale_factor; 28 | } 29 | set { 30 | _scale_factor = value; 31 | 32 | update_size (); 33 | } 34 | } 35 | 36 | public WindowSwitcherIcon (Meta.Window window, int icon_size, float scale_factor) { 37 | Object (window: window); 38 | 39 | icon = new WindowIcon (window, Utils.scale_to_int (icon_size, scale_factor)); 40 | icon.add_constraint (new Clutter.AlignConstraint (this, Clutter.AlignAxis.BOTH, 0.5f)); 41 | add_child (icon); 42 | 43 | get_accessible ().accessible_name = window.title; 44 | get_accessible ().accessible_role = LIST_ITEM; 45 | get_accessible ().notify_state_change (Atk.StateType.FOCUSABLE, true); 46 | 47 | reactive = true; 48 | 49 | this.scale_factor = scale_factor; 50 | } 51 | 52 | private void update_size () { 53 | var indicator_size = Utils.scale_to_int ( 54 | (WindowSwitcher.ICON_SIZE + WindowSwitcher.WRAPPER_PADDING * 2), 55 | scale_factor 56 | ); 57 | set_size (indicator_size, indicator_size); 58 | } 59 | 60 | protected override void draw (Cairo.Context ctx, int width, int height) { 61 | ctx.save (); 62 | ctx.set_operator (Cairo.Operator.CLEAR); 63 | ctx.paint (); 64 | ctx.clip (); 65 | ctx.reset_clip (); 66 | 67 | if (selected) { 68 | // draw rect 69 | var rgba = Drawing.StyleManager.get_instance ().theme_accent_color; 70 | ctx.set_source_rgba ( 71 | rgba.red, 72 | rgba.green, 73 | rgba.blue, 74 | rgba.alpha 75 | ); 76 | var rect_radius = Utils.scale_to_int (WRAPPER_BORDER_RADIUS, scale_factor); 77 | Drawing.Utilities.cairo_rounded_rectangle (ctx, 0, 0, width, height, rect_radius); 78 | ctx.set_operator (Cairo.Operator.SOURCE); 79 | ctx.fill (); 80 | 81 | ctx.restore (); 82 | } 83 | 84 | get_accessible ().notify_state_change (Atk.StateType.SELECTED, selected); 85 | get_accessible ().notify_state_change (Atk.StateType.FOCUSED, selected); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/WindowListener.vala: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2014 Tom Beckmann 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program 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 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | // 17 | 18 | public class Gala.WindowListener : Object { 19 | public struct WindowGeometry { 20 | Mtk.Rectangle inner; 21 | Mtk.Rectangle outer; 22 | } 23 | 24 | private static WindowListener? instance = null; 25 | 26 | public static void init (Meta.Display display) { 27 | if (instance != null) 28 | return; 29 | 30 | instance = new WindowListener (); 31 | 32 | foreach (unowned Meta.WindowActor actor in display.get_window_actors ()) { 33 | if (actor.is_destroyed ()) 34 | continue; 35 | 36 | unowned Meta.Window window = actor.get_meta_window (); 37 | if (window.window_type == Meta.WindowType.NORMAL) 38 | instance.monitor_window (window); 39 | } 40 | 41 | display.window_created.connect ((window) => { 42 | if (window.window_type == Meta.WindowType.NORMAL) 43 | instance.monitor_window (window); 44 | }); 45 | } 46 | 47 | public static unowned WindowListener get_default () requires (instance != null) { 48 | return instance; 49 | } 50 | 51 | public signal void window_on_all_workspaces_changed (Meta.Window window); 52 | 53 | private Gee.HashMap unmaximized_state_geometry; 54 | 55 | private WindowListener () { 56 | unmaximized_state_geometry = new Gee.HashMap (); 57 | } 58 | 59 | private void monitor_window (Meta.Window window) { 60 | window.notify.connect (window_notify); 61 | window.unmanaged.connect (window_removed); 62 | 63 | window_maximized_changed (window); 64 | } 65 | 66 | private void window_notify (Object object, ParamSpec pspec) { 67 | var window = (Meta.Window) object; 68 | 69 | switch (pspec.name) { 70 | case "maximized-horizontally": 71 | case "maximized-vertically": 72 | window_maximized_changed (window); 73 | break; 74 | case "on-all-workspaces": 75 | window_on_all_workspaces_changed (window); 76 | break; 77 | } 78 | } 79 | 80 | private void window_maximized_changed (Meta.Window window) { 81 | WindowGeometry window_geometry = {}; 82 | window_geometry.inner = window.get_frame_rect (); 83 | window_geometry.outer = window.get_buffer_rect (); 84 | 85 | unmaximized_state_geometry.@set (window, window_geometry); 86 | } 87 | 88 | public WindowGeometry? get_unmaximized_state_geometry (Meta.Window window) { 89 | return unmaximized_state_geometry.@get (window); 90 | } 91 | 92 | private void window_removed (Meta.Window window) { 93 | window.notify.disconnect (window_notify); 94 | window.unmanaged.disconnect (window_removed); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/meson.build: -------------------------------------------------------------------------------- 1 | gala_bin_sources = files( 2 | 'DBus.vala', 3 | 'DBusAccelerator.vala', 4 | 'DaemonManager.vala', 5 | 'DesktopIntegration.vala', 6 | 'InternalUtils.vala', 7 | 'KeyboardManager.vala', 8 | 'Main.vala', 9 | 'NotificationsManager.vala', 10 | 'NotificationStack.vala', 11 | 'PantheonShell.vala', 12 | 'PluginManager.vala', 13 | 'ScreenSaverManager.vala', 14 | 'ScreenshotManager.vala', 15 | 'SessionManager.vala', 16 | 'SuperScrollAction.vala', 17 | 'WindowListener.vala', 18 | 'WindowManager.vala', 19 | 'WindowStateSaver.vala', 20 | 'WindowTracker.vala', 21 | 'WorkspaceManager.vala', 22 | 'Zoom.vala', 23 | 'Background/Animation.vala', 24 | 'Background/Background.vala', 25 | 'Background/BackgroundCache.vala', 26 | 'Background/BackgroundContainer.vala', 27 | 'Background/BackgroundManager.vala', 28 | 'Background/BackgroundSource.vala', 29 | 'Background/BlurEffect.vala', 30 | 'Background/SystemBackground.vala', 31 | 'ColorFilters/ColorblindnessCorrectionEffect.vala', 32 | 'ColorFilters/FilterManager.vala', 33 | 'ColorFilters/MonochromeEffect.vala', 34 | 'Dialogs/AccessDialog.vala', 35 | 'Dialogs/CloseDialog.vala', 36 | 'Dialogs/InhibitShortcutsDialog.vala', 37 | 'Gestures/ActorTarget.vala', 38 | 'Gestures/Gesture.vala', 39 | 'Gestures/GestureBackend.vala', 40 | 'Gestures/GestureController.vala', 41 | 'Gestures/GestureSettings.vala', 42 | 'Gestures/GestureTarget.vala', 43 | 'Gestures/PropertyTarget.vala', 44 | 'Gestures/RootTarget.vala', 45 | 'Gestures/ScrollBackend.vala', 46 | 'Gestures/SpringTimeline.vala', 47 | 'Gestures/ToucheggBackend.vala', 48 | 'HotCorners/Barrier.vala', 49 | 'HotCorners/HotCorner.vala', 50 | 'HotCorners/HotCornerManager.vala', 51 | 'ShellClients/HideTracker.vala', 52 | 'ShellClients/ManagedClient.vala', 53 | 'ShellClients/NotificationsClient.vala', 54 | 'ShellClients/PanelWindow.vala', 55 | 'ShellClients/PositionedWindow.vala', 56 | 'ShellClients/ShellClientsManager.vala', 57 | 'ShellClients/ShellWindow.vala', 58 | 'Widgets/DwellClickTimer.vala', 59 | 'Widgets/MultitaskingView/IconGroup.vala', 60 | 'Widgets/MultitaskingView/IconGroupContainer.vala', 61 | 'Widgets/MultitaskingView/MonitorClone.vala', 62 | 'Widgets/MultitaskingView/MultitaskingView.vala', 63 | 'Widgets/MultitaskingView/StaticWindowClone.vala', 64 | 'Widgets/MultitaskingView/StaticWindowContainer.vala', 65 | 'Widgets/MultitaskingView/Tooltip.vala', 66 | 'Widgets/MultitaskingView/WindowClone.vala', 67 | 'Widgets/MultitaskingView/WindowCloneContainer.vala', 68 | 'Widgets/MultitaskingView/WindowIconActor.vala', 69 | 'Widgets/MultitaskingView/WorkspaceClone.vala', 70 | 'Widgets/MultitaskingView/WorkspaceInsertThumb.vala', 71 | 'Widgets/MultitaskingView/WorkspaceRow.vala', 72 | 'Widgets/PixelPicker.vala', 73 | 'Widgets/PointerLocator.vala', 74 | 'Widgets/SessionLocker.vala', 75 | 'Widgets/SelectionArea.vala', 76 | 'Widgets/WindowOverview.vala', 77 | 'Widgets/WindowSwitcher/WindowSwitcher.vala', 78 | 'Widgets/WindowSwitcher/WindowSwitcherIcon.vala', 79 | ) 80 | 81 | gala_bin = executable( 82 | 'gala', 83 | gala_bin_sources, 84 | dependencies: [gala_dep, gala_base_dep, pantheon_desktop_shell_dep], 85 | include_directories: config_inc_dir, 86 | install_rpath: mutter_typelib_dir, 87 | install: true, 88 | ) 89 | -------------------------------------------------------------------------------- /tools/remove_mutter_versions.py: -------------------------------------------------------------------------------- 1 | # Simple script to remove mutter version blocks from vala files up to the specified version. 2 | # 3 | # For example for a block 4 | # 5 | # #if HAS_MUTTER44 6 | # ... 7 | # #else 8 | # ... 9 | # #endif 10 | # 11 | # and a specified version of 44 or higher only the code between #if and #else will be kept. 12 | 13 | import os 14 | import re 15 | import sys 16 | 17 | class MutterBlock: 18 | def __init__(self): 19 | self.skip_block = False 20 | self.discard = False 21 | self.keep_endif = False 22 | 23 | 24 | def remove_mutter_blocks(file_path, version): 25 | print ("Removing mutter blocks from file: " + file_path + " for version: " + str(version)) 26 | 27 | with open(file_path, 'r') as file: 28 | lines = file.readlines() 29 | 30 | output_lines = [] 31 | blocks = [MutterBlock()] 32 | version_pattern = re.compile(r'(#if|#elif) (!)?HAS_MUTTER(\d+)') 33 | 34 | for line in lines: 35 | if line.startswith("#if"): 36 | blocks.append(MutterBlock()) 37 | 38 | if version_pattern.match(line): 39 | match = version_pattern.match(line) 40 | 41 | current_version = int(match.group(3)) 42 | if current_version <= version: 43 | if not blocks[-1].skip_block and match.group(2) == "!": 44 | blocks[-1].skip_block = True 45 | blocks[-1].discard = True 46 | continue 47 | elif not blocks[-1].skip_block and match.group(1) == "#elif": 48 | output_lines.append("#else\n") 49 | blocks[-1].keep_endif = True 50 | elif blocks[-1].skip_block: # we are already skipping so we probably are in an #elif block with an even lower version so we can discard right away 51 | blocks[-1].discard = True 52 | 53 | blocks[-1].skip_block = True 54 | continue 55 | elif blocks[-1].skip_block and line.strip() == '#else': 56 | blocks[-1].discard = not blocks[-1].discard 57 | continue 58 | elif line.strip() == '#endif': 59 | block = blocks.pop() 60 | if block.skip_block and not block.keep_endif: 61 | continue 62 | 63 | discard = False 64 | for b in blocks: 65 | if b.discard: 66 | discard = True 67 | break 68 | 69 | if not discard: 70 | output_lines.append(line) 71 | 72 | with open(file_path, 'w') as file: 73 | file.writelines(output_lines) 74 | 75 | def remove_recursive(file_path, version): 76 | for file in os.listdir(file_path): 77 | if os.path.isdir(file_path + "/" + file) and not file.startswith(".") and not "build" in file: 78 | remove_recursive(file_path + "/" + file, version) 79 | elif file.endswith(".vala") or file.endswith(".vapi"): 80 | remove_mutter_blocks(file_path + "/" + file, version) 81 | 82 | if __name__ == "__main__": 83 | if len(sys.argv) != 3: 84 | print("Usage: python remove_mutter_versions.py ") 85 | sys.exit(1) 86 | 87 | file_path = sys.argv[1] 88 | version = int(sys.argv[2]) 89 | 90 | if os.path.isdir(file_path): 91 | print ("Removing mutter blocks from all vala files in dir and subdirs: " + sys.argv[1] + " for version: " + sys.argv[2]) 92 | remove_recursive(file_path, version) 93 | else: 94 | remove_mutter_blocks(file_path, version) 95 | 96 | print ("Done! Also don't forget to update the meson.build files, README and remove outdated vapi.") 97 | -------------------------------------------------------------------------------- /vapi/Clutter-13-custom.vala: -------------------------------------------------------------------------------- 1 | namespace Clutter { 2 | public struct Color { 3 | [CCode (cname = "_vala_clutter_color_from_hls")] 4 | public static Clutter.Color? from_hls (float hue, float luminance, float saturation) { 5 | var color = Clutter.Color.alloc (); 6 | color.init_from_hls (hue, luminance, saturation); 7 | return color; 8 | } 9 | [CCode (cname = "_vala_clutter_color_from_pixel")] 10 | public static Clutter.Color? from_pixel (uint32 pixel) { 11 | var color = Clutter.Color.alloc (); 12 | color.init_from_pixel (pixel); 13 | return color; 14 | } 15 | [CCode (cname = "_vala_clutter_color_from_string")] 16 | public static Clutter.Color? from_string (string str) { 17 | var color = Clutter.Color.alloc (); 18 | color.init_from_string (str); 19 | return color; 20 | } 21 | [CCode (cname = "clutter_color_from_string")] 22 | public bool parse_string (string str); 23 | } 24 | 25 | public interface Container : GLib.Object { 26 | public void add (params Clutter.Actor[] actors); 27 | [CCode (cname = "clutter_container_class_find_child_property")] 28 | public class unowned GLib.ParamSpec find_child_property (string property_name); 29 | [CCode (cname = "clutter_container_class_list_child_properties")] 30 | public class unowned GLib.ParamSpec[] list_child_properties (); 31 | } 32 | 33 | public struct Units { 34 | [CCode (cname = "clutter_units_from_cm")] 35 | public Units.from_cm (float cm); 36 | [CCode (cname = "clutter_units_from_em")] 37 | public Units.from_em (float em); 38 | [CCode (cname = "clutter_units_from_em_for_font")] 39 | public Units.from_em_for_font (string font_name, float em); 40 | [CCode (cname = "clutter_units_from_mm")] 41 | public Units.from_mm (float mm); 42 | [CCode (cname = "clutter_units_from_pixels")] 43 | public Units.from_pixels (int px); 44 | [CCode (cname = "clutter_units_from_pt")] 45 | public Units.from_pt (float pt); 46 | [CCode (cname = "clutter_units_from_string")] 47 | public Units.from_string (string str); 48 | } 49 | 50 | [CCode (cheader_filename = "clutter/clutter.h", has_copy_function = false, has_destroy_function = false, has_type_id = false)] 51 | public struct Capture { 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /vapi/Clutter-14-custom.vala: -------------------------------------------------------------------------------- 1 | namespace Clutter { 2 | public struct Color { 3 | [CCode (cname = "_vala_clutter_color_from_hls")] 4 | public static Clutter.Color? from_hls (float hue, float luminance, float saturation) { 5 | var color = Clutter.Color.alloc (); 6 | color.init_from_hls (hue, luminance, saturation); 7 | return color; 8 | } 9 | [CCode (cname = "_vala_clutter_color_from_pixel")] 10 | public static Clutter.Color? from_pixel (uint32 pixel) { 11 | var color = Clutter.Color.alloc (); 12 | color.init_from_pixel (pixel); 13 | return color; 14 | } 15 | [CCode (cname = "_vala_clutter_color_from_string")] 16 | public static Clutter.Color? from_string (string str) { 17 | var color = Clutter.Color.alloc (); 18 | color.init_from_string (str); 19 | return color; 20 | } 21 | [CCode (cname = "clutter_color_from_string")] 22 | public bool parse_string (string str); 23 | } 24 | 25 | public interface Container : GLib.Object { 26 | public void add (params Clutter.Actor[] actors); 27 | [CCode (cname = "clutter_container_class_find_child_property")] 28 | public class unowned GLib.ParamSpec find_child_property (string property_name); 29 | [CCode (cname = "clutter_container_class_list_child_properties")] 30 | public class unowned GLib.ParamSpec[] list_child_properties (); 31 | } 32 | 33 | public struct Units { 34 | [CCode (cname = "clutter_units_from_cm")] 35 | public Units.from_cm (float cm); 36 | [CCode (cname = "clutter_units_from_em")] 37 | public Units.from_em (float em); 38 | [CCode (cname = "clutter_units_from_em_for_font")] 39 | public Units.from_em_for_font (string font_name, float em); 40 | [CCode (cname = "clutter_units_from_mm")] 41 | public Units.from_mm (float mm); 42 | [CCode (cname = "clutter_units_from_pixels")] 43 | public Units.from_pixels (int px); 44 | [CCode (cname = "clutter_units_from_pt")] 45 | public Units.from_pt (float pt); 46 | [CCode (cname = "clutter_units_from_string")] 47 | public Units.from_string (string str); 48 | } 49 | 50 | [CCode (cheader_filename = "clutter/clutter.h", has_copy_function = false, has_destroy_function = false, has_type_id = false)] 51 | public struct Capture { 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /vapi/Clutter-15-custom.vala: -------------------------------------------------------------------------------- 1 | namespace Clutter { 2 | public interface Container : GLib.Object { 3 | public void add (params Clutter.Actor[] actors); 4 | [CCode (cname = "clutter_container_class_find_child_property")] 5 | public class unowned GLib.ParamSpec find_child_property (string property_name); 6 | [CCode (cname = "clutter_container_class_list_child_properties")] 7 | public class unowned GLib.ParamSpec[] list_child_properties (); 8 | } 9 | 10 | public struct Units { 11 | [CCode (cname = "clutter_units_from_cm")] 12 | public Units.from_cm (float cm); 13 | [CCode (cname = "clutter_units_from_em")] 14 | public Units.from_em (float em); 15 | [CCode (cname = "clutter_units_from_em_for_font")] 16 | public Units.from_em_for_font (string font_name, float em); 17 | [CCode (cname = "clutter_units_from_mm")] 18 | public Units.from_mm (float mm); 19 | [CCode (cname = "clutter_units_from_pixels")] 20 | public Units.from_pixels (int px); 21 | [CCode (cname = "clutter_units_from_pt")] 22 | public Units.from_pt (float pt); 23 | [CCode (cname = "clutter_units_from_string")] 24 | public Units.from_string (string str); 25 | } 26 | 27 | [CCode (cheader_filename = "clutter/clutter.h", has_copy_function = false, has_destroy_function = false, has_type_id = false)] 28 | public struct Capture { 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /vapi/Clutter-15.metadata: -------------------------------------------------------------------------------- 1 | // Non mini-object 2 | ActorBox struct 3 | Margin struct 4 | PaintVolume struct 5 | Perspective struct 6 | 7 | *.ref unowned 8 | 9 | Actor 10 | .apply_transform.matrix ref 11 | .get_abs_allocation_vertices.verts out=false 12 | Event.type#method name="get_type" 13 | Image 14 | .new symbol_type="constructor" 15 | 16 | // ??? 17 | Actor.has_pointer#method name="get_has_pointer" 18 | 19 | // Not all backing symbols are deprecated 20 | Actor.pick deprecated=false 21 | 22 | // Nullable return values 23 | Actor 24 | .get_parent nullable 25 | 26 | // method/virtual-method/signal don't match 27 | Actor 28 | .event#method name="emit_event" 29 | .get_paint_volume#virtual_method name="get_paint_volume_vfunc" 30 | .get_paint_volume#virtual_method.volume out 31 | Text 32 | .activate#method name="try_activate" 33 | .insert_text#signal skip 34 | TextBuffer.get_text#virtual_method name="get_text_with_length" 35 | 36 | // Default values 37 | Stage.read_pixels 38 | .width default=-1 39 | .height default=-1 40 | Stage.paint_to_buffer 41 | .data type="uint8[]" 42 | Text 43 | .position_to_coords.line_height default=null 44 | 45 | // Skipped by g-i for unknown reasons 46 | LayoutManager 47 | .create_child_meta skip=false 48 | 49 | // Variadic arguments 50 | Backend 51 | .get_cogl_context skip=false 52 | Interval 53 | .new skip=false 54 | .get_interval skip=false 55 | .set_final skip=false 56 | .set_initial skip=false 57 | .set_interval skip=false 58 | LayoutManager 59 | .child_get skip=false 60 | .child_set skip=false 61 | 62 | // Skipped upstream for unknown reasons 63 | Interval.register_progress_func skip=false 64 | threads_add_idle skip=false 65 | threads_add_idle_full skip=false 66 | threads_add_timeout skip=false 67 | threads_add_timeout_full skip=false 68 | 69 | // struct/class confusion 70 | ActorBox 71 | .new skip 72 | .from_vertices skip 73 | Margin 74 | .new skip 75 | 76 | // Upstream 77 | Event 78 | .get_position.position out 79 | 80 | TransferFunction.get_default_luminances 81 | .min_lum_out out 82 | .max_lum_out out 83 | .ref_lum_out out 84 | 85 | FrameListenerIface skip 86 | FrameClock.new skip 87 | 88 | // Remove for clutter-2.0 89 | ///////////////////////// 90 | 91 | StageView.layout skip 92 | 93 | Stage 94 | .paint_view.redraw_clip type="Cairo.Region" 95 | 96 | // *Event should be compact classes derived from Clutter.Event 97 | Event.type skip=false 98 | AnyEvent struct=false base_type="Clutter.Event" 99 | ButtonEvent struct=false base_type="Clutter.Event" 100 | CrossingEvent struct=false base_type="Clutter.Event" 101 | DeviceEvent struct=false base_type="Clutter.Event" 102 | IMEvent struct=false base_type="Clutter.Event" 103 | KeyEvent struct=false base_type="Clutter.Event" 104 | MotionEvent struct=false base_type="Clutter.Event" 105 | PadButtonEvent struct=false base_type="Clutter.Event" 106 | PadRingEvent struct=false base_type="Clutter.Event" 107 | PadStripEvent struct=false base_type="Clutter.Event" 108 | ProximityEvent struct=false base_type="Clutter.Event" 109 | ScrollEvent struct=false base_type="Clutter.Event" 110 | TouchEvent struct=false base_type="Clutter.Event" 111 | TouchpadHoldEvent struct=false base_type="Clutter.Event" 112 | TouchpadPinchEvent struct=false base_type="Clutter.Event" 113 | TouchpadSwipeEvent struct=false base_type="Clutter.Event" 114 | 115 | // Keysyms used to be CLUTTER_X instead of CLUTTER_KEY_X 116 | *#constant skip 117 | CURRENT_TIME skip=false 118 | PRIORITY_REDRAW skip=false 119 | 120 | // Clutter devs don't like us creating nested namespaces 121 | value_* name="value_(.+)" parent="Clutter.Value" 122 | threads_* name="threads_(.+)" parent="Clutter.Threads" 123 | threads_add_idle name="add" parent="Clutter.Threads.Idle" 124 | threads_add_idle_full name="add_full" parent="Clutter.Threads.Idle" 125 | threads_add_timeout name="add" parent="Clutter.Threads.Timeout" 126 | threads_add_timeout_full name="add_full" parent="Clutter.Threads.Timeout" 127 | 128 | // There is no way to know sealed classes before GLib 2.70 129 | ColorState sealed 130 | FrameClock sealed 131 | TextureContent sealed 132 | 133 | TextureContent.new_from_texture symbol_type="constructor" 134 | 135 | // Possibly keep 136 | KEY_* skip=false name="KEY_(.+)" type="uint" parent="Clutter.Key" 137 | BUTTON_* skip=false name="BUTTON_(.+)" type="uint32" parent="Clutter.Button" 138 | EVENT_STOP skip=false type="bool" 139 | EVENT_PROPAGATE skip=false type="bool" 140 | -------------------------------------------------------------------------------- /vapi/Cogl-13.metadata: -------------------------------------------------------------------------------- 1 | * cheader_filename="cogl/cogl.h" 2 | 3 | Color struct 4 | 5 | _ColorSizeCheck skip 6 | _TextureVertexSizeCheck skip 7 | 8 | Color.equal.v1 type="Cogl.Color" 9 | Color.equal.v2 type="Cogl.Color" 10 | color_equal skip 11 | 12 | Context.free_timestamp_query.query owned 13 | 14 | Texture 15 | .get_data.data type="uint8[]" 16 | .set_data.data type="uint8[]" 17 | .set_region.data type="uint8[]" 18 | 19 | Texture2D 20 | .new_from_data skip=false 21 | .new_from_data.data array=true 22 | 23 | shader_* name="shader_(.+)" parent="Cogl.Shader" 24 | shader_* symbol_type="method" instance_idx=0 25 | 26 | Pipeline.get_layer_filters 27 | .min_filter out 28 | .mag_filter out 29 | 30 | program_* name="program_(.+)" parent="Cogl.Program" 31 | program_attach_shader symbol_type="method" instance_idx=0 32 | program_get_uniform_location symbol_type="method" instance_idx=0 33 | program_link symbol_type="method" instance_idx=0 34 | program_set_uniform_1f symbol_type="method" instance_idx=0 35 | program_set_uniform_1i symbol_type="method" instance_idx=0 36 | program_set_uniform_float symbol_type="method" instance_idx=0 37 | program_set_uniform_int symbol_type="method" instance_idx=0 38 | program_set_uniform_matrix symbol_type="method" instance_idx=0 39 | 40 | is_bitmap parent="Cogl.Object" symbol_type="method" instance_idx=0 41 | is_program parent="Cogl.Handle" 42 | is_shader parent="Cogl.Handle" 43 | is_texture parent="Cogl.Object" symbol_type="method" instance_idx=0 44 | is_context parent="Cogl.Object" symbol_type="method" instance_idx=0 45 | is_framebuffer parent="Cogl.Object" symbol_type="method" instance_idx=0 46 | is_frame_info parent="Cogl.Object" symbol_type="method" instance_idx=0 47 | is_pipeline parent="Cogl.Object" symbol_type="method" instance_idx=0 48 | is_texture_2d parent="Cogl.Object" symbol_type="method" instance_idx=0 49 | is_texture_2d_sliced parent="Cogl.Object" symbol_type="method" instance_idx=0 50 | is_snippet parent="Cogl.Object" symbol_type="method" instance_idx=0 51 | 52 | create_program type="unowned Cogl.Program" name="create" parent="Cogl.Program" 53 | create_shader type="unowned Cogl.Shader" name="create" parent="Cogl.Shader" 54 | 55 | foreach_feature parent="Cogl.Context" symbol_type="method" instance_idx=0 56 | get_graphics_reset_status parent="Cogl.Context" symbol_type="method" instance_idx=0 57 | has_feature parent="Cogl.Context" symbol_type="method" instance_idx=0 58 | 59 | Bitmap.error_quark parent="Cogl.BitmapError" name="quark" 60 | Texture.error_quark parent="Cogl.TextureError" name="quark" 61 | texture_error_quark skip 62 | Scanout.error_quark parent="Cogl.ScanoutError" name="quark" 63 | scanout_error_quark skip 64 | 65 | BitmapError errordomain 66 | BlendStringError errordomain 67 | RendererError errordomain 68 | SystemError errordomain 69 | TextureError errordomain 70 | FramebufferError errordomain 71 | ScanoutError errordomain 72 | 73 | Offscreen sealed 74 | -------------------------------------------------------------------------------- /vapi/Cogl-14-custom.vala: -------------------------------------------------------------------------------- 1 | namespace Cogl { 2 | public struct Color { 3 | [Version (since = "1.4")] 4 | [CCode (cname="cogl_color_init_from_4f")] 5 | public Color.from_4f (float red, float green, float blue, float alpha); 6 | [Version (since = "1.4")] 7 | [CCode (cname="cogl_color_init_from_4fv")] 8 | public Color.from_4fv (float color_array); 9 | [Version (since = "1.16")] 10 | [CCode (cname="cogl_color_init_from_hsl")] 11 | public Color.from_hsl (float hue, float saturation, float luminance); 12 | } 13 | [CCode (cheader_filename = "cogl/cogl.h", has_type_id = false)] 14 | [Version (since = "1.6")] 15 | public struct VertexP2 { 16 | public float x; 17 | public float y; 18 | } 19 | [CCode (cheader_filename = "cogl/cogl.h", has_type_id = false)] 20 | [Version (since = "1.6")] 21 | public struct VertexP2C4 { 22 | public float x; 23 | public float y; 24 | public uint8 r; 25 | public uint8 g; 26 | public uint8 b; 27 | public uint8 a; 28 | } 29 | [CCode (cheader_filename = "cogl/cogl.h", has_type_id = false)] 30 | [Version (since = "1.6")] 31 | public struct VertexP2T2 { 32 | public float x; 33 | public float y; 34 | public float s; 35 | public float t; 36 | } 37 | [CCode (cheader_filename = "cogl/cogl.h", has_type_id = false)] 38 | [Version (since = "1.6")] 39 | public struct VertexP2T2C4 { 40 | public float x; 41 | public float y; 42 | public float s; 43 | public float t; 44 | public uint8 r; 45 | public uint8 g; 46 | public uint8 b; 47 | public uint8 a; 48 | } 49 | [CCode (cheader_filename = "cogl/cogl.h", has_type_id = false)] 50 | [Version (since = "1.6")] 51 | public struct VertexP3 { 52 | public float x; 53 | public float y; 54 | public float z; 55 | } 56 | [CCode (cheader_filename = "cogl/cogl.h", has_type_id = false)] 57 | [Version (since = "1.6")] 58 | public struct VertexP3C4 { 59 | public float x; 60 | public float y; 61 | public float z; 62 | public uint8 r; 63 | public uint8 g; 64 | public uint8 b; 65 | public uint8 a; 66 | } 67 | [CCode (cheader_filename = "cogl/cogl.h", has_type_id = false)] 68 | [Version (since = "1.6")] 69 | public struct VertexP3T2 { 70 | public float x; 71 | public float y; 72 | public float z; 73 | public float s; 74 | public float t; 75 | } 76 | [CCode (cheader_filename = "cogl/cogl.h", has_type_id = false)] 77 | [Version (since = "1.6")] 78 | public struct VertexP3T2C4 { 79 | public float x; 80 | public float y; 81 | public float z; 82 | public float s; 83 | public float t; 84 | public uint8 r; 85 | public uint8 g; 86 | public uint8 b; 87 | public uint8 a; 88 | } 89 | [CCode (cheader_filename = "cogl/cogl.h", cprefix = "COGL_PIXEL_FORMAT_", type_id = "cogl_pixel_format_get_type ()")] 90 | public enum PixelFormat { 91 | CAIRO_ARGB32_COMPAT; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /vapi/Cogl-14.metadata: -------------------------------------------------------------------------------- 1 | * cheader_filename="cogl/cogl.h" 2 | 3 | Color struct 4 | 5 | Color.equal.v1 type="Cogl.Color" 6 | Color.equal.v2 type="Cogl.Color" 7 | color_equal skip 8 | 9 | Context.free_timestamp_query.query owned 10 | 11 | Bitmap.* skip=false 12 | Bitmap.new_for_data.data type="owned uint8[]" 13 | Bitmap.get_buffer type="unowned Cogl.Buffer?" 14 | 15 | Primitive.new skip=false 16 | 17 | Texture 18 | .get_data.data type="uint8[]" 19 | .set_data.data type="uint8[]" 20 | .set_region.data type="uint8[]" 21 | 22 | Texture2D 23 | .new_from_data skip=false 24 | 25 | create_program type="Cogl.Program" name="create" parent="Cogl.Program" 26 | create_shader type="Cogl.Shader" name="create" parent="Cogl.Shader" 27 | 28 | foreach_feature parent="Cogl.Context" symbol_type="method" instance_idx=0 29 | get_graphics_reset_status parent="Cogl.Context" symbol_type="method" instance_idx=0 30 | has_feature parent="Cogl.Context" symbol_type="method" instance_idx=0 31 | 32 | Bitmap.error_quark parent="Cogl.BitmapError" name="quark" 33 | Texture.error_quark parent="Cogl.TextureError" name="quark" 34 | Scanout.error_quark parent="Cogl.ScanoutError" name="quark" 35 | 36 | BitmapError errordomain 37 | BlendStringError errordomain 38 | RendererError errordomain 39 | SystemError errordomain 40 | TextureError errordomain 41 | FramebufferError errordomain 42 | ScanoutError errordomain 43 | 44 | is_framebuffer skip 45 | blit_framebuffer parent="Cogl.Framebuffer" symbol_type="method" instance_idx=0 name="blit" 46 | 47 | Onscreen 48 | .add_dirty_callback unowned 49 | .add_frame_callback unowned 50 | -------------------------------------------------------------------------------- /vapi/Cogl-15-custom.vala: -------------------------------------------------------------------------------- 1 | namespace Cogl { 2 | public struct Color { 3 | [CCode (cname="cogl_color_init_from_4f")] 4 | public Color.from_4f (float red, float green, float blue, float alpha); 5 | [CCode (cname="cogl_color_init_from_hsl")] 6 | public Color.from_hsl (float hue, float saturation, float luminance); 7 | [CCode (cname = "_vala_cogl_color_from_string")] 8 | public static Cogl.Color? from_string (string str) { 9 | Cogl.Color color = {}; 10 | if (color.init_from_string (str)) 11 | return color; 12 | 13 | return null; 14 | } 15 | } 16 | [CCode (cheader_filename = "cogl/cogl.h", has_type_id = false)] 17 | public struct VertexP2 { 18 | public float x; 19 | public float y; 20 | } 21 | [CCode (cheader_filename = "cogl/cogl.h", has_type_id = false)] 22 | public struct VertexP2C4 { 23 | public float x; 24 | public float y; 25 | public uint8 r; 26 | public uint8 g; 27 | public uint8 b; 28 | public uint8 a; 29 | } 30 | [CCode (cheader_filename = "cogl/cogl.h", has_type_id = false)] 31 | public struct VertexP2T2 { 32 | public float x; 33 | public float y; 34 | public float s; 35 | public float t; 36 | } 37 | [CCode (cheader_filename = "cogl/cogl.h", has_type_id = false)] 38 | public struct VertexP2T2C4 { 39 | public float x; 40 | public float y; 41 | public float s; 42 | public float t; 43 | public uint8 r; 44 | public uint8 g; 45 | public uint8 b; 46 | public uint8 a; 47 | } 48 | [CCode (cheader_filename = "cogl/cogl.h", has_type_id = false)] 49 | public struct VertexP3 { 50 | public float x; 51 | public float y; 52 | public float z; 53 | } 54 | [CCode (cheader_filename = "cogl/cogl.h", has_type_id = false)] 55 | public struct VertexP3T2 { 56 | public float x; 57 | public float y; 58 | public float z; 59 | public float s; 60 | public float t; 61 | } 62 | [CCode (cheader_filename = "cogl/cogl.h", cprefix = "COGL_PIXEL_FORMAT_", type_id = "cogl_pixel_format_get_type ()")] 63 | public enum PixelFormat { 64 | CAIRO_ARGB32_COMPAT; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /vapi/Cogl-15.metadata: -------------------------------------------------------------------------------- 1 | * cheader_filename="cogl/cogl.h" 2 | 3 | Color struct 4 | 5 | Color.equal.v1 type="Cogl.Color" 6 | Color.equal.v2 type="Cogl.Color" 7 | Color.from_string name="init_from_string" 8 | 9 | Context.free_timestamp_query.query owned 10 | 11 | Bitmap.* skip=false 12 | Bitmap.new_for_data.data type="owned uint8[]" 13 | Bitmap.get_buffer type="unowned Cogl.Buffer?" 14 | 15 | Primitive.new skip=false 16 | 17 | Texture 18 | .get_data.data type="uint8[]" 19 | .set_data.data type="uint8[]" 20 | .set_region.data type="uint8[]" 21 | 22 | Texture2D 23 | .new_from_data skip=false 24 | 25 | Texture.error_quark parent="Cogl.TextureError" name="quark" 26 | Scanout.error_quark parent="Cogl.ScanoutError" name="quark" 27 | 28 | RendererError errordomain 29 | SystemError errordomain 30 | TextureError errordomain 31 | FramebufferError errordomain 32 | ScanoutError errordomain 33 | 34 | blit_framebuffer parent="Cogl.Framebuffer" symbol_type="method" instance_idx=0 name="blit" 35 | meta_texture_foreach_in_region parent="Cogl.Texture" symbol_type="method" instance_idx=0 name="foreach_in_region" 36 | 37 | Onscreen 38 | .add_frame_callback unowned 39 | 40 | A_BIT parent="Cogl.Bits" name="A" 41 | BGR_BIT parent="Cogl.Bits" name="BGR" 42 | AFIRST_BIT parent="Cogl.Bits" name="AFIRST" 43 | PREMULT_BIT parent="Cogl.Bits" name="PREMULT" 44 | DEPTH_BIT parent="Cogl.Bits" name="DEPTH" 45 | STENCIL_BIT parent="Cogl.Bits" name="STENCIL" 46 | PIXEL_FORMAT_MAX_PLANES parent = "Cogl.PixelFormat" name="MAX_PLANES" 47 | -------------------------------------------------------------------------------- /vapi/Mtk-13.metadata: -------------------------------------------------------------------------------- 1 | Rectangle struct 2 | -------------------------------------------------------------------------------- /vapi/Mtk-14.metadata: -------------------------------------------------------------------------------- 1 | Rectangle struct 2 | RECTANGLE_MAX_STACK_RECTS parent="Mtk.Rectangle" name="MAX_STACK_RECTS" 3 | REGION_BUILDER_MAX_LEVELS parent="Mtk.RegionBuilder" name="MAX_LEVELS" 4 | -------------------------------------------------------------------------------- /vapi/Mtk-15.metadata: -------------------------------------------------------------------------------- 1 | Rectangle struct 2 | RECTANGLE_MAX_STACK_RECTS parent="Mtk.Rectangle" name="MAX_STACK_RECTS" 3 | REGION_BUILDER_MAX_LEVELS parent="Mtk.RegionBuilder" name="MAX_LEVELS" 4 | 5 | MONITOR_ALL_TRANSFORMS parent="Mtk.MonitorTransform" name="ALL" 6 | MONITOR_N_TRANSFORMS skip 7 | -------------------------------------------------------------------------------- /vapi/atk-bridge-2.0.vapi: -------------------------------------------------------------------------------- 1 | [CCode (cheader_filename = "atk-bridge.h", lower_case_cprefix = "atk_bridge_")] 2 | namespace AtkBridge { 3 | public static int adaptor_init ([CCode (array_length_pos = 0.9)] ref unowned string[] argv); 4 | public static void adaptor_cleanup (); 5 | public static void set_event_context (GLib.MainContext cnx); 6 | } 7 | -------------------------------------------------------------------------------- /vapi/config.vapi: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2011 Robert Dyer, Rico Tzschichholz 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program 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 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | // 17 | 18 | [CCode (cprefix = "", lower_case_cprefix = "", cheader_filename = "config.h")] 19 | namespace Config 20 | { 21 | public const string GETTEXT_PACKAGE; 22 | public const string LOCALEDIR; 23 | public const string DATADIR; 24 | public const string PKGDATADIR; 25 | public const string VERSION; 26 | public const string PLUGINDIR; 27 | public const string RESOURCEPATH; 28 | } 29 | -------------------------------------------------------------------------------- /vapi/gnome-desktop-3.0.deps: -------------------------------------------------------------------------------- 1 | atk 2 | cairo 3 | gio-2.0 4 | gdesktopenums-3.0 5 | gdk-pixbuf-2.0 6 | gdk-3.0 7 | gtk+-3.0 8 | -------------------------------------------------------------------------------- /vapi/libmutter-13.deps: -------------------------------------------------------------------------------- 1 | libmutter.deps -------------------------------------------------------------------------------- /vapi/libmutter-13.vapi: -------------------------------------------------------------------------------- 1 | libmutter.vapi -------------------------------------------------------------------------------- /vapi/libmutter-14.deps: -------------------------------------------------------------------------------- 1 | libmutter-13.deps -------------------------------------------------------------------------------- /vapi/libmutter-14.vapi: -------------------------------------------------------------------------------- 1 | libmutter-13.vapi -------------------------------------------------------------------------------- /vapi/libmutter-15.deps: -------------------------------------------------------------------------------- 1 | libmutter-14.deps -------------------------------------------------------------------------------- /vapi/libmutter-15.vapi: -------------------------------------------------------------------------------- 1 | libmutter-14.vapi -------------------------------------------------------------------------------- /vapi/libmutter.deps: -------------------------------------------------------------------------------- 1 | cairo 2 | gdesktopenums-3.0 3 | gdk-3.0 4 | gdk-pixbuf-2.0 5 | gtk+-3.0 6 | x11 7 | xfixes-4.0 8 | -------------------------------------------------------------------------------- /vapi/libsystemd.vapi: -------------------------------------------------------------------------------- 1 | [CCode (cheader_filename = "systemd/sd-daemon.h")] 2 | namespace Systemd.Daemon { 3 | [CCode (cname="sd_notify")] 4 | int notify([CCode (type="int")]bool unset_environment, string state); 5 | 6 | [CCode (cname="sd_notifyf")] 7 | int notifyf([CCode (type="int")]bool unset_environment, string format, ...); 8 | 9 | [CCode (cname="sd_pid_notify")] 10 | int pid_notify(Posix.pid_t pid, [CCode (type="int")]bool unset_environment, string state); 11 | 12 | [CCode (cname="sd_pid_notifyf")] 13 | int pid_notifyf(Posix.pid_t pid, [CCode (type="int")]bool unset_environment, string format, ...); 14 | 15 | [CCode (cname="sd_pid_notify_with_fds")] 16 | int pid_notify_with_fds(Posix.pid_t pid, [CCode (type="int")]bool unset_environment, string state, int[] fds); 17 | } 18 | 19 | -------------------------------------------------------------------------------- /vapi/mutter-clutter-13.deps: -------------------------------------------------------------------------------- 1 | atk 2 | cairo 3 | pango 4 | json-glib-1.0 5 | mutter-cogl-13 6 | graphene-gobject-1.0 7 | -------------------------------------------------------------------------------- /vapi/mutter-clutter-13.vapi: -------------------------------------------------------------------------------- 1 | mutter-clutter.vapi -------------------------------------------------------------------------------- /vapi/mutter-clutter-14.deps: -------------------------------------------------------------------------------- 1 | atk 2 | cairo 3 | pango 4 | json-glib-1.0 5 | mutter-cogl-14 6 | graphene-gobject-1.0 7 | -------------------------------------------------------------------------------- /vapi/mutter-clutter-14.vapi: -------------------------------------------------------------------------------- 1 | mutter-clutter-13.vapi -------------------------------------------------------------------------------- /vapi/mutter-clutter-15.deps: -------------------------------------------------------------------------------- 1 | atk 2 | cairo 3 | pango 4 | json-glib-1.0 5 | mutter-cogl-15 6 | graphene-gobject-1.0 7 | -------------------------------------------------------------------------------- /vapi/mutter-clutter-15.vapi: -------------------------------------------------------------------------------- 1 | mutter-clutter-14.vapi -------------------------------------------------------------------------------- /vapi/mutter-cogl-13.deps: -------------------------------------------------------------------------------- 1 | mutter-cogl.deps -------------------------------------------------------------------------------- /vapi/mutter-cogl-13.vapi: -------------------------------------------------------------------------------- 1 | mutter-cogl.vapi -------------------------------------------------------------------------------- /vapi/mutter-cogl-14.deps: -------------------------------------------------------------------------------- 1 | pango 2 | glib-2.0 3 | gio-2.0 4 | mutter-mtk-14 5 | x11 6 | -------------------------------------------------------------------------------- /vapi/mutter-cogl-15.deps: -------------------------------------------------------------------------------- 1 | pango 2 | glib-2.0 3 | gio-2.0 4 | mutter-mtk-15 5 | x11 6 | -------------------------------------------------------------------------------- /vapi/mutter-cogl-15.vapi: -------------------------------------------------------------------------------- 1 | mutter-cogl-14.vapi -------------------------------------------------------------------------------- /vapi/mutter-cogl-pango-13.vapi: -------------------------------------------------------------------------------- 1 | mutter-cogl-pango.vapi -------------------------------------------------------------------------------- /vapi/mutter-cogl-pango-14.vapi: -------------------------------------------------------------------------------- 1 | mutter-cogl-pango-13.vapi -------------------------------------------------------------------------------- /vapi/mutter-cogl-pango-15.vapi: -------------------------------------------------------------------------------- 1 | mutter-cogl-pango-14.vapi -------------------------------------------------------------------------------- /vapi/mutter-cogl-pango.vapi: -------------------------------------------------------------------------------- 1 | /* mutter-cogl-pango-6.vapi generated by vapigen, do not modify. */ 2 | 3 | [CCode (cprefix = "CoglPango", gir_namespace = "CoglPango", gir_version = "6", lower_case_cprefix = "cogl_pango_")] 4 | namespace CoglPango { 5 | [CCode (cheader_filename = "cogl-pango.h", type_id = "cogl_pango_renderer_get_type ()")] 6 | public class Renderer : Pango.Renderer { 7 | [CCode (has_construct_function = false)] 8 | protected Renderer (); 9 | [NoAccessorMethod] 10 | public Cogl.Context context { construct; } 11 | } 12 | [CCode (cheader_filename = "cogl-pango.h")] 13 | public interface FontMap : Pango.CairoFontMap, GLib.Object { 14 | #if !HAS_MUTTER47 15 | public void clear_glyph_cache (); 16 | #endif 17 | public Pango.Context create_context (); 18 | public unowned Pango.Renderer get_renderer (); 19 | #if !HAS_MUTTER47 20 | public bool get_use_mipmapping (); 21 | #endif 22 | public static Pango.FontMap @new (); 23 | public void set_resolution (double dpi); 24 | #if !HAS_MUTTER47 25 | public void set_use_mipmapping (bool value); 26 | #endif 27 | } 28 | #if HAS_MUTTER47 29 | [CCode (cheader_filename = "cogl-pango.h", instance_pos = 1.9)] 30 | public delegate void PipelineSetup (Cogl.Pipeline pipeline); 31 | #endif 32 | [CCode (cheader_filename = "cogl-pango.h")] 33 | public static void ensure_glyph_cache_for_layout (Pango.Layout layout); 34 | } 35 | -------------------------------------------------------------------------------- /vapi/mutter-cogl.deps: -------------------------------------------------------------------------------- 1 | pango 2 | glib-2.0 3 | gio-2.0 4 | -------------------------------------------------------------------------------- /vapi/mutter-mtk-14.vapi: -------------------------------------------------------------------------------- 1 | mutter-mtk-13.vapi -------------------------------------------------------------------------------- /vapi/mutter-mtk-15.vapi: -------------------------------------------------------------------------------- 1 | mutter-mtk-14.vapi -------------------------------------------------------------------------------- /vapi/wayland-server.deps: -------------------------------------------------------------------------------- 1 | posix 2 | -------------------------------------------------------------------------------- /vapi/xfixes-4.0.vapi: -------------------------------------------------------------------------------- 1 | /* xfixes-4.0.vapi generated by vapigen, do not modify. */ 2 | /* Manually edited, so feel free to add and adjust it directly */ 3 | 4 | [CCode (cprefix = "X", gir_namespace = "xfixes", gir_version = "4.0", lower_case_cprefix = "X_")] 5 | namespace X { 6 | namespace Fixes { 7 | [CCode (cheader_filename = "X11/extensions/Xfixes.h", cname = "XFixesCreateRegion")] 8 | public static X.XserverRegion create_region (X.Display display, [CCode (array_length = true)] X.Xrectangle[] rectangles); 9 | [CCode (cheader_filename = "X11/extensions/Xfixes.h", cname = "XFixesCreateRegionFromWindow")] 10 | public static X.XserverRegion create_region_from_window (X.Display display, X.Window window, int shape_kind); 11 | [CCode (cheader_filename = "X11/extensions/Xfixes.h", cname = "XFixesDestroyRegion")] 12 | public static void destroy_region (X.Display display, X.XserverRegion region); 13 | [CCode (cheader_filename = "X11/extensions/Xfixes.h", cname = "XFixesSetWindowShapeRegion")] 14 | public static void set_window_shape_region (X.Display display, X.Window win, int shape_kind, int x_off, int y_off, XserverRegion region); 15 | } 16 | namespace Shape { 17 | [CCode (cheader_filename = "X11/extensions/shape.h", cname = "XShapeGetRectangles")] 18 | public static X.Rectangle* get_rectangles (X.Display display, X.Window win, int kind, out int count, out int ordering); 19 | [CCode (cheader_filename = "X11/extensions/shape.h", cname = "XShapeCombineRectangles")] 20 | public static void combine_rectangles (X.Display display, X.Window win, int kind, int x, int y, [CCode (array_length_cname = "count", type = "XRectangle*")] X.Rectangle[] rectangles, int op, int ordering); 21 | } 22 | [SimpleType] 23 | [CCode (cheader_filename = "X11/extensions/Xfixes.h", cname = "XserverRegion", has_type_id = false)] 24 | public struct XserverRegion { 25 | } 26 | [SimpleType] 27 | [CCode (cheader_filename = "X11/Xlib.h", cname = "XRectangle", has_type_id = false)] 28 | public struct Xrectangle { 29 | public short x; 30 | public short y; 31 | public ushort width; 32 | public ushort height; 33 | } 34 | } 35 | --------------------------------------------------------------------------------