Skip to content

Commit

Permalink
Default icon and some refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
ueffel committed Mar 17, 2018
1 parent 082427d commit b213dab
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 65 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.idea
*.bak
8 changes: 7 additions & 1 deletion build_package.cmd
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,10 @@ if exist %PACKAGE_NAME%.keypirinha-package (
del %PACKAGE_NAME%.keypirinha-package
)
echo Using "%SEVENZIP%" to pack
"%SEVENZIP%" a -mx9 -tzip %PACKAGE_NAME%.keypirinha-package -x!%~nx0 -xr!.git *
"%SEVENZIP%" a -mx9 ^
-tzip "%PACKAGE_NAME%.keypirinha-package" ^
-x!%~nx0 ^
-xr!.git ^
-x@.gitignore ^
-x!.gitignore ^
*
Binary file added kill.ico
Binary file not shown.
3 changes: 2 additions & 1 deletion kill.ini
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@
# * kill_by_name_admin - Same as above but requests elevated rights
# * kill_by_id - Kills only the selected process (one single process)
# * kill_by_id_admin - Same as above but requests elevated rights
# Default: kill_by_id
#default_action = kill_by_id

# If set to "yes", filters out every process that doesn't have visible window
#
# Default: no
# hide_background = no
#hide_background = no
117 changes: 54 additions & 63 deletions kill.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,11 @@
WAIT_FAILED = 0xFFFFFFFF

class Kill(kp.Plugin):
"""
Plugin that lists running processes with name and commandline (if
available) and kills the selected process(es)
"""Plugin that lists running processes with name and commandline (if available) and kills the selected process(es)
"""

def __init__(self):
"""
Default constructor and initializing internal attributes
"""Default constructor and initializing internal attributes
"""
super().__init__()
self._processes = []
Expand All @@ -43,18 +40,17 @@ def __init__(self):
self._icons = {}
self._default_action = "kill_by_id"
self._hide_background = False
# self._debug = True
self._default_icon = None
self._debug = False

def on_events(self, flags):
"""
Reloads the package config when its changed
"""Reloads the package config when its changed
"""
if flags & kp.Events.PACKCONFIG:
self._read_config()

def _read_config(self):
"""
Reads the default action from the config
"""Reads the default action from the config
"""
settings = self.load_settings()

Expand All @@ -75,8 +71,7 @@ def _read_config(self):
self._hide_background = settings.get_bool("hide_background", "main", False)

def on_start(self):
"""
Creates the actions for killing the processes and register them
"""Creates the actions for killing the processes and register them
"""
self._read_config()
kill_by_name = self.create_action(
Expand Down Expand Up @@ -119,15 +114,15 @@ def on_start(self):
)

self._actions.append(kill_and_restart_by_id)

self.set_actions(RESTARTABLE, self._actions)

self._default_icon = self.load_icon("res://{}/kill.ico".format(self.package_full_name()))
self.dbg(self._default_icon)

def on_catalog(self):
"""
Adds the kill command to the catalog
"""Adds the kill command to the catalog
"""
catalog = []

killcmd = self.create_item(
category=kp.ItemCategory.KEYWORD,
label="Kill:",
Expand All @@ -136,31 +131,30 @@ def on_catalog(self):
args_hint=kp.ItemArgsHint.REQUIRED,
hit_hint=kp.ItemHitHint.KEEPALL
)

catalog.append(killcmd)

self.set_catalog(catalog)

def _get_icon(self, source):
"""Tries to load the first icon within the source which should be a path to an executable
"""
Tries to load the first icon within the source which should be a
path to an executable
"""
if not source:
return self._default_icon

if source in self._icons:
return self._icons[source]
else:
try:
icon = self.load_icon("@{},0".format(source))
self._icons[source] = icon
except ValueError:
self.dbg("Icon loading failed :( {}".format(source))
self.dbg("Icon loading failed :( ", source)
icon = None
if not icon:
return self._default_icon
return icon

def _get_processes(self):
"""
Creates the list of running processes, when the Keypirinha Box is
triggered
"""Creates the list of running processes, when the Keypirinha Box is triggered
"""
start_time = time.time()

Expand All @@ -177,9 +171,11 @@ def _get_processes(self):
elapsed = time.time() - start_time

self.info("Found {} running processes in {:0.1f} seconds".format(len(self._processes), elapsed))
self.dbg("{} icons loaded".format(len(self._icons)))
self.dbg(len(self._icons), "icons loaded")

def _get_windows(self):
"""Gets the list of open windows create a mapping between pid and hwnd
"""
try:
handles = AltTab.list_alttab_windows()
except OSError:
Expand All @@ -189,15 +185,15 @@ def _get_windows(self):

for hwnd in handles:
try:
(_, proc_id) = AltTab.get_window_thread_process_id(hwnd)
_, proc_id = AltTab.get_window_thread_process_id(hwnd)
self._processes_with_window[proc_id] = hwnd
except OSError:
continue

def _get_processes_from_com_object(self, wmi):
"""
Creates the list of running processes
Windows Management COMObject (WMI) to get the running processes
"""Creates the list of running processes
Uses Windows Management COMObject (WMI) to get the running processes
"""
result_wmi = wmi.ExecQuery("SELECT ProcessId, Caption, Name, ExecutablePath, CommandLine "
+ "FROM Win32_Process")
Expand Down Expand Up @@ -259,10 +255,10 @@ def _get_processes_from_com_object(self, wmi):
self._processes.append(item)

def _get_processes_from_ext_call(self):
"""
FALLBACK
Creates the list of running processes
Uses Windows' "wmic.exe" tool to get the running processes
"""FALLBACK
Creates the list of running processes
Uses Windows' "wmic.exe" tool to get the running processes
"""
# Using external call to wmic to get the list of running processes
startupinfo = subprocess.STARTUPINFO()
Expand All @@ -288,7 +284,7 @@ def _get_processes_from_ext_call(self):
outstr = output.decode(enc)
break
except UnicodeDecodeError:
self.dbg(enc + " threw exception")
self.dbg(enc, "threw exception")

info = {}
for line in outstr.splitlines():
Expand Down Expand Up @@ -326,9 +322,9 @@ def _get_processes_from_ext_call(self):
label = info["Caption"]
if not self._hide_background:
if is_foreground:
label = label + " (foreground)"
label = "{} (foreground)".format(label)
else:
label = label + " (background)"
label = "{} (background)".format(label)

item = self.create_item(
category=category,
Expand All @@ -353,19 +349,17 @@ def _get_processes_from_ext_call(self):
info[label] = value

def on_deactivated(self):
"""
Emptys the process list, when Keypirinha Box is closed
"""Emptys the process list and frees the icon handles, when Keypirinha Box is closed
"""
self._processes_with_window = {}
self._processes = []

# for ico in self._icons.values():
# ico.free()
# self._icons = {}
for ico in self._icons.values():
ico.free()
self._icons = {}

def on_suggest(self, user_input, items_chain):
"""
Sets the list of running processes as suggestions
"""Sets the list of running processes as suggestions
"""
if not items_chain:
return
Expand All @@ -379,8 +373,7 @@ def on_suggest(self, user_input, items_chain):
self.set_suggestions(self._processes, kp.Match.FUZZY, kp.Sort.SCORE_DESC)

def on_execute(self, item, action):
"""
Executes the selected (or default) kill action on the selected item
"""Executes the selected (or default) kill action on the selected item
"""
# get default action if no action was explicitly selected
if action is None:
Expand All @@ -394,8 +387,7 @@ def on_execute(self, item, action):
self._kill_process_normal(item, action.name())

def _kill_process_normal(self, target_item, action_name):
"""
Kills the selected process(es) using the windows api
"""Kills the selected process(es) using the windows api
"""
target_name, target_pid = target_item.target().split("|")
if "kill_by_name" in action_name:
Expand Down Expand Up @@ -433,47 +425,48 @@ def _kill_process_normal(self, target_item, action_name):
pid = int(target_pid)
proc_handle = KERNEL.OpenProcess(PROCESS_TERMINATE | SYNCHRONIZE, False, pid)
if not proc_handle:
self.warn("OpenProcess failed, ErrorCode: {}".format(KERNEL.GetLastError()))
self.warn("OpenProcess failed, ErrorCode: {}", KERNEL.GetLastError())
return
success = KERNEL.TerminateProcess(proc_handle, 1)
if not success:
self.warn("TerminateProcess failed, ErrorCode: {}".format(KERNEL.GetLastError()))
self.warn("TerminateProcess failed, ErrorCode:", KERNEL.GetLastError())
return

self.dbg("Waiting for exit")
result = KERNEL.WaitForSingleObject(proc_handle, ct.wintypes.DWORD(3000))
timeout = ct.wintypes.DWORD(10000)
result = KERNEL.WaitForSingleObject(proc_handle, timeout)
if result == WAIT_FAILED:
self.warn("WaitForSingleObject failed, ErrorCode: {}".format(KERNEL.GetLastError()))
self.warn("WaitForSingleObject failed, ErrorCode:", KERNEL.GetLastError())
return
if result == WAIT_TIMEOUT:
self.warn("WaitForSingleObject timed out.")
return
if result != WAIT_OBJECT_0:
self.warn("Something weird happened in WaitForSingleObject: {}".format(result))
self.warn("Something weird happened in WaitForSingleObject:", result)
return

databag = eval(target_item.data_bag())
self.dbg(databag)
self.dbg("databag for process: ", databag)
if "CommandLine" not in databag:
self.dbg("No commandline, cannot restart")
self.warn("No commandline, cannot restart")
return

cmd = ct.wintypes.LPCWSTR(databag["CommandLine"])
argc = ct.c_int(0)
argv = CommandLineToArgvW(cmd, ct.byref(argc))
if argc.value <= 0:
self.dbg("No args parsed")
return

args = [argv[i] for i in range(0, argc.value)]
self.dbg(args)
self.dbg("CommandLine args from CommandLineToArgvW:", args)
if args[0] == '' or args[0].isspace():
args[0] = databag["ExecutablePath"]
self.dbg(args)
self.dbg("Restarting:", args)
kpu.shell_execute(args[0], args[1:])

def _kill_process_admin(self, target_item, action_name):
"""
Kills the selected process(es) using a call to windows' taskkill.exe
with elevated rights
"""Kills the selected process(es) using a call to windows' taskkill.exe with elevated rights
"""
target_name, target_pid = target_item.target().split("|")
args = ["taskkill", "/F"]
Expand All @@ -488,7 +481,5 @@ def _kill_process_admin(self, target_item, action_name):
# process id
args.append(target_pid)

self.dbg("Calling: {}".format(args))

# show no window when executing
self.dbg("Calling: ", args)
kpu.shell_execute(args[0], args[1:], verb="runas", show=subprocess.SW_HIDE)

0 comments on commit b213dab

Please sign in to comment.