Merge branch 'master' of github.com:rad4day/dotfiles
This commit is contained in:
commit
5b6ead4d23
@ -144,7 +144,7 @@ floating_modifier $mod
|
||||
# Screensaver || ThinkVantage
|
||||
bindsym XF86ScreenSaver exec xautolock -locknow
|
||||
bindsym XF86Battery exec xautolock -locknow
|
||||
bindsym XF86Launch1 exec "xautolock -locknow; sleep 1; xset dpms force off"
|
||||
bindsym XF86Launch1 exec "xautolock -locknow; sync; systemctl suspend-then-hibernate"
|
||||
|
||||
# Lock screen
|
||||
bindsym $mod+Ctrl+l exec "xautolock -locknow; sleep 1; xset dpms force off"
|
||||
|
@ -1,18 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
function run {
|
||||
if ! pgrep $1 ;
|
||||
then
|
||||
$@&
|
||||
fi
|
||||
}
|
||||
run compton
|
||||
run kwalletd5
|
||||
run xscreensaver -nosplash
|
||||
nitrogen --restore &
|
||||
|
||||
# Programms
|
||||
run nextcloud
|
||||
#run telegram-desktop
|
||||
#run discord
|
||||
#run thunderbird
|
@ -1,24 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
import subprocess
|
||||
|
||||
|
||||
class Dmenu(object):
|
||||
def __init__(self, items: list):
|
||||
with open(os.path.dirname(sys.argv[0]) + "/dmenu.json") as fp:
|
||||
self._dmenu = json.load(fp)["dmenu"]
|
||||
self._items = items
|
||||
|
||||
def run(self):
|
||||
"""Returns (exitCode, stdout)"""
|
||||
p1 = subprocess.run(
|
||||
self._dmenu,
|
||||
input="\n".join(self._items),
|
||||
encoding="utf-8",
|
||||
stdout=subprocess.PIPE,
|
||||
)
|
||||
return (p1.returncode, p1.stdout)
|
@ -1,30 +0,0 @@
|
||||
{
|
||||
"dmenu": [
|
||||
"dmenu",
|
||||
"-i",
|
||||
"-l",
|
||||
"6",
|
||||
"-x",
|
||||
"550",
|
||||
"-y",
|
||||
"400",
|
||||
"-w",
|
||||
"500",
|
||||
"-h",
|
||||
"20",
|
||||
"-dim",
|
||||
"0.2",
|
||||
"-p",
|
||||
"Do",
|
||||
"-fn",
|
||||
"Inconsolata-14:normal",
|
||||
"-nb",
|
||||
"#3F3F3F",
|
||||
"-nf",
|
||||
"#DCDCCC",
|
||||
"-sb",
|
||||
"#1E2320",
|
||||
"-sf",
|
||||
"#F0DFAF"
|
||||
]
|
||||
}
|
@ -1,145 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import sqlite3
|
||||
import json
|
||||
import argparse
|
||||
import sys
|
||||
import os
|
||||
from modules import Application, MPC
|
||||
from Dmenu import Dmenu
|
||||
|
||||
del sys.path[0]
|
||||
sys.path.insert(0, os.path.dirname(sys.argv[0]))
|
||||
|
||||
|
||||
# CONFIG
|
||||
loadModules = [Application(), MPC()]
|
||||
|
||||
con = sqlite3.connect(os.path.dirname(sys.argv[0]) + "/database.sqlite")
|
||||
|
||||
# ARGUMENTS PARSER
|
||||
|
||||
parser = argparse.ArgumentParser(description="Smart Dropdown Launcher for AwesomeWM")
|
||||
parser.add_argument(
|
||||
"--create",
|
||||
dest="FLAG_CREATE",
|
||||
action="store_const",
|
||||
const=True,
|
||||
default=False,
|
||||
help="Force TABLE \
|
||||
CREATION",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--build",
|
||||
dest="FLAG_BUILD",
|
||||
action="store_const",
|
||||
const=True,
|
||||
default=False,
|
||||
help="Force Build \
|
||||
the Database",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--truncate",
|
||||
dest="FLAG_TRUNCATE",
|
||||
action="store_const",
|
||||
const=True,
|
||||
default=False,
|
||||
help="Truncate\
|
||||
Database during build",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
|
||||
# Helper functions
|
||||
|
||||
|
||||
def create_db():
|
||||
command = "CREATE TABLE entries(`ID` INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE, `Name` TEXT, `json` TEXT, `hits` INTEGER NOT NULL DEFAULT 0, `disabled` INTEGER NOT NULL DEFAULT 0, `type` TEXT NOT NULL DEFAULT 'file', `file` TEXT);"
|
||||
with con:
|
||||
cur = con.cursor()
|
||||
cur.execute(command)
|
||||
con.commit()
|
||||
|
||||
|
||||
def retrieve_db():
|
||||
rows = []
|
||||
with con:
|
||||
con.row_factory = sqlite3.Row
|
||||
cur = con.cursor()
|
||||
cur.execute("SELECT * FROM entries;")
|
||||
ro = cur.fetchall()
|
||||
for r in ro:
|
||||
r = dict(r)
|
||||
r["json"] = json.loads(r["json"])
|
||||
rows.append(r)
|
||||
return rows
|
||||
|
||||
|
||||
def build_db():
|
||||
entries = {}
|
||||
for mod in loadModules:
|
||||
entries.update(mod.build_db())
|
||||
for k, v in entries.items():
|
||||
if "Exec" in v["json"]:
|
||||
with con:
|
||||
con.cursor().execute(
|
||||
"INSERT INTO entries(Name, json, file, type, disabled) VALUES(?, ?, ?, ?, ?)",
|
||||
(k, json.dumps(v["json"]), v["file"], v["type"], v["disabled"]),
|
||||
)
|
||||
|
||||
|
||||
def build_menu():
|
||||
entries = []
|
||||
db = retrieve_db()
|
||||
for mod in loadModules:
|
||||
entries += mod.build_menu([x for x in db if x["type"] == mod.db_type])
|
||||
|
||||
# sort by hits
|
||||
return sorted(entries, key=lambda i: i[2], reverse=True)
|
||||
|
||||
|
||||
def run_program(data):
|
||||
with con:
|
||||
cur = con.cursor()
|
||||
cur.execute("UPDATE entries SET hits=? WHERE ID=?", (data[2] + 1, data[0]))
|
||||
cur.execute("SELECT type FROM entries WHERE ID=?", (data[0],))
|
||||
con.commit()
|
||||
typ = dict(cur.fetchone())["type"]
|
||||
for mod in loadModules:
|
||||
if mod.db_type == typ:
|
||||
mod.call(data[1])
|
||||
|
||||
|
||||
if args.FLAG_CREATE:
|
||||
with con:
|
||||
con.cursor().execute("DROP TABLE IF EXISTS entries;")
|
||||
create_db()
|
||||
# set BUILD flag so the database gets rebuilt too
|
||||
args.FLAG_BUILD = True
|
||||
|
||||
if args.FLAG_BUILD:
|
||||
if args.FLAG_TRUNCATE:
|
||||
with con:
|
||||
con.cursor().execute("DELETE FROM entries")
|
||||
con.cursor().execute("DELETE FROM sqlite_sequence WHERE name='entries'")
|
||||
con.commit()
|
||||
build_db()
|
||||
|
||||
entries = build_menu()
|
||||
p1 = Dmenu([x[1] for x in entries]).run()
|
||||
|
||||
if p1[0] != 0:
|
||||
# error on escape
|
||||
exit(1)
|
||||
|
||||
selected = list(filter(lambda x: p1[1].strip().startswith(x[1]), entries))
|
||||
if selected == []:
|
||||
# -> terminal module? None-Type modules?
|
||||
pass
|
||||
else:
|
||||
# use actual user input
|
||||
selected = (selected[0][0], p1[1].rstrip(), selected[0][2])
|
||||
run_program(selected)
|
||||
|
||||
con.close()
|
@ -1,128 +0,0 @@
|
||||
from .Module import Module as _Module
|
||||
import locale as _locale
|
||||
import subprocess as _subprocess
|
||||
import shlex as _shlex
|
||||
from pathlib import Path as _Path
|
||||
from os import listdir as _listdir
|
||||
from os.path import isfile as _isfile, join as _join
|
||||
|
||||
|
||||
class Application(_Module):
|
||||
|
||||
def __init__(self):
|
||||
self.db_type = "Application"
|
||||
self._home = str(_Path.home())
|
||||
self._lang = _locale.getlocale()[0].split("_")[0].strip()
|
||||
self._dirs = ["/usr/share/applications", self._home + "/.local/share/applications"]
|
||||
self._references = {}
|
||||
|
||||
def build_db(self):
|
||||
"""Function which adds entries to the database.
|
||||
returns dict with:
|
||||
Name, json, disabled, type, "file" """
|
||||
db = {}
|
||||
for d in self._dirs:
|
||||
for fi in _listdir(d):
|
||||
if _isfile(_join(d, fi)):
|
||||
fc = self._scan_file(_join(d, fi))
|
||||
for k, v in fc.items():
|
||||
db.update({k: {
|
||||
"Name": k,
|
||||
"json": v,
|
||||
"disabled": (("NoDisplay" in v and v["NoDisplay"] == "true") or
|
||||
("Hidden" in v and v["Hidden"] == "true")),
|
||||
"file": v['file'],
|
||||
"type": self.db_type
|
||||
}})
|
||||
return db
|
||||
|
||||
def update_db(self, database: dict):
|
||||
"""Function which updates entries in the database.
|
||||
returns dict with modified/deleted/added database entries"""
|
||||
entries = self.build_db()
|
||||
dbremove = []
|
||||
# dbKey == id, dbValue dict of fileds
|
||||
for dbKey, dbValue in database:
|
||||
if dbValue["type"] == self.db_type:
|
||||
if dbValue["Name"] not in entries:
|
||||
dbremove.append(dbKey)
|
||||
else:
|
||||
# update all values managed by this module
|
||||
for k, v in entries[dbValue["Name"]]:
|
||||
dbValue[k] = v
|
||||
# remove no more existing entries
|
||||
for i in dbremove:
|
||||
database.pop(i)
|
||||
return database
|
||||
|
||||
def build_menu(self, items: dict):
|
||||
"""Builds the menu entries.
|
||||
return list of tuples (id, name, hits)"""
|
||||
# we only get entries of our app type so no problem here
|
||||
# json is already unjsonified
|
||||
NAME_PREFIX="run "
|
||||
NAME_POSTFIX=" (%PATH%)"
|
||||
entries = []
|
||||
for r in items:
|
||||
identifier=(NAME_PREFIX + r['Name'] + NAME_POSTFIX).replace("%PATH%", r['json']['Exec'])
|
||||
entries.append((r['ID'], identifier, r['hits']))
|
||||
if ("Terminal" not in r["json"]):
|
||||
r['json']["Terminal"] = "false"
|
||||
self._references[identifier] = (r['json']["Exec"], r['json']["Terminal"], r['file'], r['Name'])
|
||||
|
||||
return entries
|
||||
|
||||
def call(self, cmd: str):
|
||||
"""Handles the selected entry"""
|
||||
# find the entry
|
||||
reference = list(filter(lambda x: cmd.startswith(x), self._references.keys()))
|
||||
entry = reference[0]
|
||||
cmd = cmd.replace(entry, "").lstrip()
|
||||
# Just call the program
|
||||
_subprocess.Popen(_shlex.split(self._expand_fieldcodes(self._references[entry][0], cmd, reference)),
|
||||
encoding="utf-8",
|
||||
shell=(self._references[entry][1] == "true"))
|
||||
|
||||
def _scan_file(self, fi):
|
||||
entries = {}
|
||||
with open(fi, encoding="utf-8", mode="r") as f:
|
||||
data = {}
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if line.startswith("["): # and line.rstrip() != "[Desktop Entry]":
|
||||
data["header"] = line.strip("[]")
|
||||
if "Name" in data and "Exec" in data:
|
||||
data['file'] = fi
|
||||
entries[data["Name"]] = data
|
||||
data = {}
|
||||
if "=" in line:
|
||||
s = line.split("=")
|
||||
if "[" in s[0] and "]" in s[0]:
|
||||
if "[" + self._lang + "]" in s[0]:
|
||||
data[s[0].replace("[" + self._lang + "]", "").strip()] = s[1]
|
||||
elif s[0] != "Name" or "Name" not in data.keys():
|
||||
data[s[0]] = s[1]
|
||||
|
||||
if "Name" in data:
|
||||
data['file'] = fi
|
||||
entries[data["Name"]] = data
|
||||
return entries
|
||||
|
||||
def _expand_fieldcodes(self, entry: str, cmd: str, reference):
|
||||
fieldcodes = ['%f', '%F', '%u', '%U', '%i', '%c', '%k'] # todo implement %i as expand icon-key
|
||||
for fc in range(0, len(fieldcodes)):
|
||||
fieldcodes[fc] = fieldcodes[fc] in entry
|
||||
if True in fieldcodes:
|
||||
if '%k' in entry:
|
||||
entry = entry.replace('%k', '"' + reference[2] + "'")
|
||||
if '%c' in entry:
|
||||
entry = entry.replace('%c', '"' + reference[3] + "'")
|
||||
if '%i' in entry:
|
||||
entry = entry.replace(' %i', "")
|
||||
if '%f' in entry or '%F' in entry or '%u' in entry or '%U' in entry:
|
||||
entry = entry.replace('%f', cmd)
|
||||
entry = entry.replace('%F', cmd)
|
||||
entry = entry.replace('%u', cmd)
|
||||
entry = entry.replace('%U', cmd)
|
||||
cmd = ""
|
||||
return (entry + " " + cmd).rstrip()
|
@ -1,118 +0,0 @@
|
||||
from .Module import Module as _Module
|
||||
import locale as _locale
|
||||
from pathlib import Path as _Path
|
||||
from Dmenu import Dmenu
|
||||
import subprocess as _subprocess
|
||||
|
||||
|
||||
class MPC(_Module):
|
||||
|
||||
def __init__(self):
|
||||
self.db_type = "MPC"
|
||||
self._home = str(_Path.home())
|
||||
self._lang = _locale.getlocale()[0].split("_")[0].strip()
|
||||
self._dirs = ["/usr/share/applications", self._home + "/.local/share/applications"]
|
||||
self.replace = True
|
||||
|
||||
def build_db(self):
|
||||
"""Function which adds entries to the database.
|
||||
returns dict with:
|
||||
Name, json, disabled, type, "file" """
|
||||
|
||||
# we only add an generic Submenu entry.
|
||||
db = {"Media Player Control [MPC]": {
|
||||
"Name": "Media Player Control [MPC]",
|
||||
"json": "",
|
||||
"disabled": False,
|
||||
"file": "none",
|
||||
"type": self.db_type
|
||||
}}
|
||||
return db
|
||||
|
||||
def update_db(self, database: dict):
|
||||
"""Function which updates entries in the database.
|
||||
returns dict with modified/deleted/added database entries"""
|
||||
return self.build_db()
|
||||
|
||||
def build_menu(self, items: dict):
|
||||
"""Builds the menu entries.
|
||||
return list of tuples (id, name, hits)"""
|
||||
# we only get entries of our app type so no problem here
|
||||
# json is already unjsonified
|
||||
entries = []
|
||||
for r in items:
|
||||
entries.append((r['ID'], r['Name'], r['hits']))
|
||||
|
||||
return entries
|
||||
|
||||
def gatherInfo(self):
|
||||
out = {}
|
||||
infoprocess = _subprocess.run("mpc", stdout=_subprocess.PIPE, shell=True)
|
||||
info = infoprocess.stdout.decode("utf8").split("\n")
|
||||
if len(info) == 4:
|
||||
status = [x.split(":") for x in info[2].split(" ")]
|
||||
|
||||
out["song"] = info[0]
|
||||
out["playing"] = "[playing]" in info[1]
|
||||
|
||||
else:
|
||||
status = [x.split(":") for x in info[0].split(" ")]
|
||||
|
||||
out["replace"] = self.replace
|
||||
status = [x for x in status if len(x) == 2]
|
||||
|
||||
for i in status:
|
||||
i[0] = i[0].strip()
|
||||
i[1] = i[1].strip()
|
||||
if i[1] == "off":
|
||||
out[i[0]] = False
|
||||
elif i[1] == "on":
|
||||
out[i[0]] = True
|
||||
else:
|
||||
out[i[0]] = i[1]
|
||||
return out
|
||||
|
||||
def buildStatusMenu(self):
|
||||
info = self.gatherInfo()
|
||||
if info["replace"]:
|
||||
playlists = ['MODE: REPLACE']
|
||||
else:
|
||||
playlists = ['MODE: APPEND']
|
||||
|
||||
if info["random"]:
|
||||
playlists += ['RANDOM: on']
|
||||
else:
|
||||
playlists += ['RANDOM: off']
|
||||
|
||||
return (len(playlists), playlists)
|
||||
|
||||
def handleStatusMenu(self, text: str):
|
||||
if text.startswith("MODE: "):
|
||||
self.replace = not self.replace
|
||||
elif text.startswith("RANDOM: "):
|
||||
_subprocess.run("mpc random", shell=True)
|
||||
|
||||
def call(self, cmd: str):
|
||||
"""Handles the selected entry"""
|
||||
# our menu entry was selected, time to create and show the submenu
|
||||
while True:
|
||||
infolen, playlists = self.buildStatusMenu()
|
||||
|
||||
playprocess = _subprocess.run("mpc lsplaylists", stdout=_subprocess.PIPE, shell=True)
|
||||
playlists += playprocess.stdout.decode("utf8").split("\n")
|
||||
menu = Dmenu(playlists)
|
||||
ex = menu.run()
|
||||
|
||||
if ex[0] == 0:
|
||||
if ex[1].rstrip() in playlists[0:infolen]:
|
||||
self.handleStatusMenu(ex[1].rstrip())
|
||||
continue
|
||||
# user selected an entry
|
||||
# mpc clear(?) -> mpc load ex[1] -> mpc play
|
||||
command = "mpc load '" + ex[1].rstrip() + "'"
|
||||
if self.replace:
|
||||
command = "mpc clear; " + command + "; mpc play"
|
||||
_subprocess.run(command, shell=True)
|
||||
break
|
||||
else:
|
||||
break
|
@ -1,25 +0,0 @@
|
||||
class Module(object):
|
||||
"""Abstract class, implement: build_db, update_db, build_menu, call"""
|
||||
|
||||
def __init__(self, obj):
|
||||
pass
|
||||
|
||||
def build_db():
|
||||
"""Function which adds entries to the database.
|
||||
returns dict with:
|
||||
Name, json, disabled, type, "file" """
|
||||
raise NotImplementedError("Should have implemented this")
|
||||
|
||||
def update_db(database: dict):
|
||||
"""Function which updates entries in the database.
|
||||
returns dict with modified/deleted/added database entries"""
|
||||
raise NotImplementedError("Should have implemented this")
|
||||
|
||||
def build_menu(items: dict):
|
||||
"""Builds the menu entries.
|
||||
return list of tuples (id, name, hits)"""
|
||||
raise NotImplementedError("Should have implemented this")
|
||||
|
||||
def call(entry: str):
|
||||
"""Handles the selected entry"""
|
||||
raise NotImplementedError("Should have implemented this")
|
@ -1,2 +0,0 @@
|
||||
from .Application import Application
|
||||
from .MPC import MPC
|
Loading…
Reference in New Issue
Block a user