'use strict'; import Adw from 'gi://Adw'; import Gtk from 'gi://Gtk'; import Gdk from 'gi://Gdk'; import GLib from 'gi://GLib'; import { ExtensionPreferences, gettext as _ } from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js'; import * as Config from 'resource:///org/gnome/Shell/Extensions/js/misc/config.js' const [major, minor] = Config.PACKAGE_VERSION.split('.').map(s => Number(s)); export default class GjsOskPreferences extends ExtensionPreferences { fillPreferencesWindow(window) { const UIFolderPath = this.dir.get_child('ui').get_path(); let iconTheme = Gtk.IconTheme.get_for_display(Gdk.Display.get_default()); iconTheme.add_search_path(UIFolderPath + `/icons`); const settings = this.getSettings('org.gnome.shell.extensions.gjsosk'); const page1 = new Adw.PreferencesPage({ title: _("General"), icon_name: "general-symbolic" }); const behaviorGroup = new Adw.PreferencesGroup({ title: _("Behavior") }); page1.add(behaviorGroup); const layoutRow = new Adw.ExpanderRow({ title: _('Layout') }); behaviorGroup.add(layoutRow); const layoutLandscapeRow = new Adw.ActionRow({ title: _('Landscape Layout') }); layoutRow.add_row(layoutLandscapeRow); let layouts; let [okL, contentsL] = GLib.file_get_contents(this.path + '/physicalLayouts.json'); if (okL) { layouts = JSON.parse(contentsL); } let layoutList = Object.keys(layouts); let layoutLandscapeDrop = Gtk.DropDown.new_from_strings(layoutList); layoutLandscapeDrop.valign = Gtk.Align.CENTER; layoutLandscapeDrop.selected = settings.get_int("layout-landscape"); layoutLandscapeRow.add_suffix(layoutLandscapeDrop); layoutLandscapeRow.activatable_widget = layoutLandscapeDrop; const layoutPortraitRow = new Adw.ActionRow({ title: _('Portrait Layout') }); layoutRow.add_row(layoutPortraitRow); let layoutPortraitDrop = Gtk.DropDown.new_from_strings(layoutList); layoutPortraitDrop.valign = Gtk.Align.CENTER; layoutPortraitDrop.selected = settings.get_int("layout-portrait"); layoutPortraitRow.add_suffix(layoutPortraitDrop); layoutPortraitRow.activatable_widget = layoutPortraitDrop; const enableDragRow = new Adw.ActionRow({ title: _('Enable Dragging') }); behaviorGroup.add(enableDragRow); const dragEnableDT = new Gtk.Switch({ active: settings.get_boolean('enable-drag'), valign: Gtk.Align.CENTER, }); enableDragRow.add_suffix(dragEnableDT); enableDragRow.activatable_widget = dragEnableDT; const indEnabledRow = new Adw.ActionRow({ title: _('Enable Panel Indicator') }); behaviorGroup.add(indEnabledRow); const indEnabled = new Gtk.Switch({ active: settings.get_boolean("indicator-enabled"), valign: Gtk.Align.CENTER, }); indEnabledRow.add_suffix(indEnabled); indEnabledRow.activatable_widget = indEnabled; const row1t5 = new Adw.ActionRow({ title: _('Open upon clicking in a text field') }); behaviorGroup.add(row1t5); let dragOptList = [_("Never"), _("Only on Touch"), _("Always")]; let dragOpt = Gtk.DropDown.new_from_strings(dragOptList); dragOpt.valign = Gtk.Align.CENTER; dragOpt.selected = settings.get_int("enable-tap-gesture"); row1t5.add_suffix(dragOpt); row1t5.activatable_widget = dragOpt; const portraitSizing = new Adw.ExpanderRow({ title: _('Portrait Sizing') }); behaviorGroup.add(portraitSizing); let pW = new Adw.ActionRow({ title: _('Width (%)') }) let pH = new Adw.ActionRow({ title: _('Height (%)') }) let numChanger_pW = Gtk.SpinButton.new_with_range(0, 100, 5); numChanger_pW.value = settings.get_int('portrait-width-percent'); numChanger_pW.valign = Gtk.Align.CENTER; pW.add_suffix(numChanger_pW); pW.activatable_widget = numChanger_pW; let numChanger_pH = Gtk.SpinButton.new_with_range(0, 100, 5); numChanger_pH.value = settings.get_int('portrait-height-percent'); numChanger_pH.valign = Gtk.Align.CENTER; pH.add_suffix(numChanger_pH); pH.activatable_widget = numChanger_pH; portraitSizing.add_row(pW); portraitSizing.add_row(pH); const landscapeSizing = new Adw.ExpanderRow({ title: _('Landscape Sizing') }); behaviorGroup.add(landscapeSizing); let lW = new Adw.ActionRow({ title: _('Width (%)') }); let lH = new Adw.ActionRow({ title: _('Height (%)') }); let numChanger_lW = Gtk.SpinButton.new_with_range(0, 100, 5); numChanger_lW.value = settings.get_int('landscape-width-percent'); numChanger_lW.valign = Gtk.Align.CENTER; lW.add_suffix(numChanger_lW); lW.activatable_widget = numChanger_lW; let numChanger_lH = Gtk.SpinButton.new_with_range(0, 100, 5); numChanger_lH.value = settings.get_int('landscape-height-percent'); numChanger_lH.valign = Gtk.Align.CENTER; lH.add_suffix(numChanger_lH); lH.activatable_widget = numChanger_lH; landscapeSizing.add_row(lW); landscapeSizing.add_row(lH); const defaultMonitor = new Adw.ActionRow({ title: _('Default Monitor') }) behaviorGroup.add(defaultMonitor); let monitors = []; const display = Gdk.Display.get_default(); if (display && "get_monitors" in display) { const monitorsAvailable = display.get_monitors(); for (let idx = 0; idx < monitorsAvailable.get_n_items(); idx++) { const monitor = monitorsAvailable.get_item(idx); monitors.push(monitor); } } let monitorDrop = Gtk.DropDown.new_from_strings(monitors.map(m => m.get_model())) monitorDrop.valign = Gtk.Align.CENTER; let currentMonitorMap = {}; let currentMonitors; if (settings.get_string("default-monitor").includes(";")) { currentMonitors = settings.get_string("default-monitor").split(";") } else { currentMonitors = [("1:" + monitors[0].get_connector())] } for (var i of currentMonitors) { let tmp = i.split(":"); currentMonitorMap[tmp[0]] = tmp[1] + ""; } if (!Object.keys(currentMonitorMap).includes(monitors.length + "")) { let allConfigs = Object.keys(currentMonitorMap).map(Number.parseInt).sort(); currentMonitorMap[monitors.length + ""] = allConfigs[allConfigs.length - 1]; } let index = monitors.map(m => { return m.get_connector() }).indexOf(currentMonitorMap[monitors.length + ""]); if (index == -1) { index = 0 } monitorDrop.selected = index; defaultMonitor.add_suffix(monitorDrop); defaultMonitor.activatable_widget = monitorDrop; const defaultPosition = new Adw.ActionRow({ title: _('Default Position') }); behaviorGroup.add(defaultPosition); let posList = [ _("Top Left"), _("Top Center"), _("Top Right"), _("Center Left"), _("Center"), _("Center Right"), _("Bottom Left"), _("Bottom Center"), _("Bottom Right") ]; let snapDrop = Gtk.DropDown.new_from_strings(posList); snapDrop.valign = Gtk.Align.CENTER; snapDrop.selected = settings.get_int("default-snap"); defaultPosition.add_suffix(snapDrop); defaultPosition.activatable_widget = snapDrop; const soundPlayRow = new Adw.ActionRow({ title: _('Play sound') }); behaviorGroup.add(soundPlayRow); const soundPlayDT = new Gtk.Switch({ active: settings.get_boolean('play-sound'), valign: Gtk.Align.CENTER, }); soundPlayRow.add_suffix(soundPlayDT); soundPlayRow.activatable_widget = soundPlayDT; const appearanceGroup = new Adw.PreferencesGroup({ title: _("Appearance") }); page1.add(appearanceGroup); const colorRow = new Adw.ExpanderRow({ title: _("Color") }) appearanceGroup.add(colorRow); const lightCol = new Adw.ActionRow({ title: _('Light Mode') }); colorRow.add_row(lightCol) let rgba = new Gdk.RGBA(); rgba.parse("rgba(" + settings.get_double("background-r") + ", " + settings.get_double("background-g") + ", " + settings.get_double("background-b") + ", " + settings.get_double("background-a") + ")"); let colorButton = new Gtk.ColorButton({ rgba: rgba, use_alpha: true, valign: Gtk.Align.CENTER }); lightCol.add_suffix(colorButton); lightCol.activatable_widget = colorButton; const darkCol = new Adw.ActionRow({ title: _('Dark Mode') }); colorRow.add_row(darkCol) let rgba_d = new Gdk.RGBA(); rgba_d.parse("rgba(" + settings.get_double("background-r-dark") + ", " + settings.get_double("background-g-dark") + ", " + settings.get_double("background-b-dark") + ", " + settings.get_double("background-a-dark") + ")"); let colorButton_d = new Gtk.ColorButton({ rgba: rgba_d, use_alpha: true, valign: Gtk.Align.CENTER }); darkCol.add_suffix(colorButton_d); darkCol.activatable_widget = colorButton_d; const systemAccCol = new Adw.ActionRow({ title: _("Use System Accent Color") }) colorRow.add_row(systemAccCol) const systemAccColEnabled = new Gtk.Switch({ active: settings.get_boolean("system-accent-col"), valign: Gtk.Align.CENTER }) systemAccCol.add_suffix(systemAccColEnabled) systemAccCol.activatable_widget = systemAccColEnabled systemAccCol.set_sensitive(major >= 47) lightCol.set_sensitive(!settings.get_boolean("system-accent-col")); darkCol.set_sensitive(!settings.get_boolean("system-accent-col")); let fontSize = new Adw.ActionRow({ title: _('Font Size (px)') }); appearanceGroup.add(fontSize); let numChanger_font = Gtk.SpinButton.new_with_range(0, 100, 1); numChanger_font.value = settings.get_int('font-size-px'); numChanger_font.valign = Gtk.Align.CENTER; fontSize.add_suffix(numChanger_font); fontSize.activatable_widget = numChanger_font; const fontBoldRow = new Adw.ActionRow({ title: _("Bold Font") }) appearanceGroup.add(fontBoldRow) const fontBoldEnabled = new Gtk.Switch({ active: settings.get_boolean("font-bold"), valign: Gtk.Align.CENTER }) fontBoldRow.add_suffix(fontBoldEnabled) fontBoldRow.activatable_widget = fontBoldEnabled let borderSpacing = new Adw.ActionRow({ title: _('Border Spacing (px)') }); appearanceGroup.add(borderSpacing); let numChanger_bord = Gtk.SpinButton.new_with_range(0, 10, 1); numChanger_bord.value = settings.get_int('border-spacing-px'); numChanger_bord.valign = Gtk.Align.CENTER; borderSpacing.add_suffix(numChanger_bord); borderSpacing.activatable_widget = numChanger_bord; let outerSpacing = new Adw.ActionRow({ title: _('Outer Spacing (px)') }); appearanceGroup.add(outerSpacing); let numChanger_outer = Gtk.SpinButton.new_with_range(0, 30, 1); numChanger_outer.value = settings.get_int('outer-spacing-px'); numChanger_outer.valign = Gtk.Align.CENTER; outerSpacing.add_suffix(numChanger_outer); outerSpacing.activatable_widget = numChanger_outer; let snapSpacing = new Adw.ActionRow({ title: _('Drag snap spacing (px)') }); appearanceGroup.add(snapSpacing); let numChanger_snap = Gtk.SpinButton.new_with_range(0, 50, 5); numChanger_snap.value = settings.get_int('snap-spacing-px'); numChanger_snap.valign = Gtk.Align.CENTER; snapSpacing.add_suffix(numChanger_snap); snapSpacing.activatable_widget = numChanger_snap; const roundCorners = new Adw.ActionRow({ title: _('Round Corners') }); appearanceGroup.add(roundCorners); const roundKeyCDT = new Gtk.Switch({ active: settings.get_boolean('round-key-corners'), valign: Gtk.Align.CENTER, }); roundCorners.add_suffix(roundKeyCDT); roundCorners.activatable_widget = roundKeyCDT; const showIcon = new Adw.ActionRow({ title: _('Show Special Key Icons') }); appearanceGroup.add(showIcon); const showIconDT = new Gtk.Switch({ active: settings.get_boolean('show-icons'), valign: Gtk.Align.CENTER, }); showIcon.add_suffix(showIconDT); showIcon.activatable_widget = showIconDT; window.add(page1); let page2 = new Adw.PreferencesPage({ title: _("About"), icon_name: 'info-symbolic', }); let contribute_icon_pref_group = new Adw.PreferencesGroup(); let icon_box = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL, margin_top: 24, margin_bottom: 24, spacing: 18, }); let icon_image = new Gtk.Image({ icon_name: "input-keyboard-symbolic", pixel_size: 128, }); let label_box = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL, spacing: 6, }); let label = new Gtk.Label({ label: "GJS OSK", wrap: true, }); let context = label.get_style_context(); context.add_class("title-1"); let another_label = new Gtk.Label({ label: _("Autorelease ") + `776e35f` }); let links_pref_group = new Adw.PreferencesGroup(); let code_row = new Adw.ActionRow({ icon_name: "code-symbolic", title: _("More Information, submit feedback, and get help") }); let github_link = new Gtk.LinkButton({ label: "Github", uri: "https://github.com/Vishram1123/gjs-osk", }); let icons_credit = new Adw.ActionRow({ icon_name: "app-icon-design-symbolic", title: _("Icons sourced from") }); let remixicon_link = new Gtk.LinkButton({ label: "RemixIcon", uri: "https://remixicon.com/", }); code_row.add_suffix(github_link); code_row.set_activatable_widget(github_link); links_pref_group.add(code_row); icons_credit.add_suffix(remixicon_link); icons_credit.set_activatable_widget(remixicon_link); links_pref_group.add(icons_credit); label_box.append(label); label_box.append(another_label); icon_box.append(icon_image); icon_box.append(label_box); contribute_icon_pref_group.add(icon_box); page2.add(contribute_icon_pref_group); page2.add(links_pref_group); window.add(page2); settings.bind("layout-landscape", layoutLandscapeDrop, "selected", 0); settings.bind("layout-portrait", layoutPortraitDrop, "selected", 0); settings.bind("enable-drag", dragEnableDT, "active", 0); settings.bind("enable-tap-gesture", dragOpt, "selected", 0); settings.bind("indicator-enabled", indEnabled, "active", 0); settings.bind("portrait-width-percent", numChanger_pW, "value", 0); settings.bind("portrait-height-percent", numChanger_pH, "value", 0); settings.bind("landscape-width-percent", numChanger_lW, "value", 0); settings.bind("landscape-height-percent", numChanger_lH, "value", 0); colorButton.connect("color-set", () => { settings.set_double("background-r", Math.round(colorButton.get_rgba().red * 255)); settings.set_double("background-g", Math.round(colorButton.get_rgba().green * 255)); settings.set_double("background-b", Math.round(colorButton.get_rgba().blue * 255)); settings.set_double("background-a", colorButton.get_rgba().alpha); }) colorButton_d.connect("color-set", () => { settings.set_double("background-r-dark", Math.round(colorButton_d.get_rgba().red * 255)); settings.set_double("background-g-dark", Math.round(colorButton_d.get_rgba().green * 255)); settings.set_double("background-b-dark", Math.round(colorButton_d.get_rgba().blue * 255)); settings.set_double("background-a-dark", colorButton_d.get_rgba().alpha); }) settings.bind("font-size-px", numChanger_font, "value", 0); settings.bind("font-bold", fontBoldEnabled, "active", 0) settings.bind("border-spacing-px", numChanger_bord, "value", 0); settings.bind("outer-spacing-px", numChanger_outer, "value", 0); settings.bind("snap-spacing-px", numChanger_snap, "value", 0) settings.bind("round-key-corners", roundKeyCDT, "active", 0); settings.bind("play-sound", soundPlayDT, "active", 0); settings.bind("show-icons", showIconDT, "active", 0) settings.bind("default-snap", snapDrop, "selected", 0); monitorDrop.connect("notify::selected", () => { currentMonitorMap[monitors.length + ""] = monitors.map(m => { return m.get_connector() })[monitorDrop.selected]; let representation = []; for (var k of Object.keys(currentMonitorMap)) { representation.push(k + ":" + currentMonitorMap[k]) } settings.set_string("default-monitor", representation.join(";")) }) systemAccColEnabled.connect("state-set", () => { settings.set_boolean("system-accent-col", systemAccColEnabled.active) lightCol.set_sensitive(!settings.get_boolean("system-accent-col")); darkCol.set_sensitive(!settings.get_boolean("system-accent-col")); }) window.connect("close-request", () => { settings.set_int("layout-landscape", layoutLandscapeDrop.selected); settings.set_int("layout-portrait", layoutPortraitDrop.selected); settings.set_boolean("enable-drag", dragEnableDT.active); settings.set_int("enable-tap-gesture", dragOpt.selected); settings.set_boolean("indicator-enabled", indEnabled.active); settings.set_int("portrait-width-percent", numChanger_pW.value); settings.set_int("portrait-height-percent", numChanger_pH.value); settings.set_int("landscape-width-percent", numChanger_lW.value); settings.set_int("landscape-height-percent", numChanger_lH.value); settings.set_double("background-r", Math.round(colorButton.get_rgba().red * 255)); settings.set_double("background-g", Math.round(colorButton.get_rgba().green * 255)); settings.set_double("background-b", Math.round(colorButton.get_rgba().blue * 255)); settings.set_double("background-a", colorButton.get_rgba().alpha); settings.set_double("background-r-dark", Math.round(colorButton_d.get_rgba().red * 255)); settings.set_double("background-g-dark", Math.round(colorButton_d.get_rgba().green * 255)); settings.set_double("background-b-dark", Math.round(colorButton_d.get_rgba().blue * 255)); settings.set_double("background-a-dark", colorButton_d.get_rgba().alpha); settings.set_int("font-size-px", numChanger_font.value); settings.set_boolean("font-bold", fontBoldEnabled.active) settings.set_int("border-spacing-px", numChanger_bord.value); settings.set_int("outer-spacing-px", numChanger_outer.value); settings.set_int("snap-spacing-px", numChanger_snap.value) settings.set_boolean("round-key-corners", roundKeyCDT.active); settings.set_boolean("play-sound", soundPlayDT.active); settings.set_boolean("show-icons", showIconDT.active) settings.set_int("default-snap", snapDrop.selected); currentMonitorMap[monitors.length + ""] = monitors.map(m => { return m.get_connector() })[monitorDrop.selected]; let representation = []; for (var k of Object.keys(currentMonitorMap)) { representation.push(k + ":" + currentMonitorMap[k]) } settings.set_string("default-monitor", representation.join(";")) settings.set_boolean("system-accent-col", systemAccColEnabled.active) }) } };