From fd50d66608a7161f4b8ee0c865096d36ebcbb588 Mon Sep 17 00:00:00 2001 From: Kwaadpepper Date: Wed, 23 Sep 2015 08:05:20 +0200 Subject: [PATCH] Linux Fix and improvements Fix the deadlock issue caused by --sync (removed --sync since it is useless) Fix the Chromebased since it needs focus before send input Fix Firefox bug with xdotool since invisible window is returned by xdotool --visible-only Add xdotool --desktop to search for compatibility purpose Add dependency to wmctrl Add Opera support Add Chromium support Add Midori support Add QupZilla support Add Konqueror support Add Vivaldi support Add custom window support for linux only Add Firefox Nightly builds support (should be the same on mac, linux and windows) --- BrowserRefresh.py | 28 ++++++++- README.md | 19 +++++- linux/__init__.py | 144 ++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 168 insertions(+), 23 deletions(-) diff --git a/BrowserRefresh.py b/BrowserRefresh.py index 9fee847..aa44df2 100644 --- a/BrowserRefresh.py +++ b/BrowserRefresh.py @@ -50,6 +50,21 @@ def run(self, args, activate=True, if 'chrome' in browsers: refresher.chrome() + if 'chromium' in browsers and _os == 'Linux': + refresher.chromium() + + if 'konqueror' in browsers and _os == 'Linux': + refresher.konqueror() + + if 'midori' in browsers and _os == 'Linux': + refresher.midori() + + if 'qupzilla' in browsers and _os == 'Linux': + refresher.qupzilla() + + if 'vivaldi' in browsers and _os == 'Linux': + refresher.vivaldi() + if 'canary' in browsers and _os == 'Darwin': refresher.canary() @@ -65,6 +80,9 @@ def run(self, args, activate=True, if 'firefox' in browsers: refresher.firefox() + if 'nightly' in browsers and _os == 'Linux': + refresher.nightly() + if 'firefoxdev' in browsers and _os == 'Darwin': refresher.firefox_dev() @@ -77,5 +95,13 @@ def run(self, args, activate=True, if 'iron' in browsers and _os == 'Windows': refresher.iron() - if 'palemoon' in browsers and _os == 'Windows': + if 'palemoon' in browsers and _os in ['Windows', 'Linux']: refresher.palemoon() + + if _os == 'Linux': + for browser in browsers: + customWindow = browser.split(':')[1] if 'custom:' in browser else False + customCommand = customWindow.split(',')[1] if ',' in customWindow else False + customWindow = customWindow.split(',')[0] if ',' in customWindow else False + if customWindow: + refresher.custom(customWindow, customCommand) diff --git a/README.md b/README.md index da48739..ac349fc 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ git clone https://github.com/gcollazo/BrowserRefresh-Sublime.git "Browser Refres Install xdotool: ``` -sudo apt-get install xdotool +sudo apt-get install xdotool wmctrl ``` ### 2. Configure Key Bindings @@ -64,15 +64,28 @@ Specify which browsers to refresh on command. The default is `chrome` which will |---------------------------|--------------|-----------------| | Google Chrome | `chrome` | Mac, Win, Linux | | Google Chrome Canary | `canary` | Mac, Win | +| Chromium | `chromium | Linux | | Safari | `safari` | Mac, Win | | WebKit | `webkit` | Mac | | Firefox | `firefox` | Mac, Win, Linux | | Firefox Developer Edition | `firefoxdev` | Mac | -| Opera | `opera` | Mac, Win | +| Firefox Nightly | `nightly` | Linux | +| Opera | `opera` | Mac, Win, Linux | | Internet Explorer | `ie` | Win | | SRWare Iron | `iron` | Win | | Yandex | `yandex` | Mac | -| Pale Moon | `palemoon` | Win | +| Pale Moon | `palemoon` | Win,Linux | +| Konqueror | `konqueror` | Linux | +| Midori | `midori` | Linux | +| Qupzilla | `qupzilla` | Linux | +| Vivaldi | `vivaldi` | Linux | + +**Linux special** + +You can optionnally try to send any key on any window with a special browser argument +**"browsers" : ["custom:opera,ctrl+F5"]** + +Keep in mind this is only for convenience purpose, it is absolutely not garranteed this method actually works ## Contributions If you have the time to make this plugin better feel free to fork and submit a pull request. diff --git a/linux/__init__.py b/linux/__init__.py index eaf4908..f15f10a 100644 --- a/linux/__init__.py +++ b/linux/__init__.py @@ -1,15 +1,32 @@ import sublime -from subprocess import call - +from subprocess import call, Popen, PIPE, STDOUT class LinuxBrowserRefresh: def __init__(self, activate_browser): - # activate_browser is always true on Windows since you can't - # send keys to an inactive window programmatically. We ignore it. self.activate_browser = activate_browser def chrome(self): - self.SendKeysToAllWindows('google-chrome', 'F5') + # need to force ctrl+F5 here + self.SendKeyToAllWebkitBasedNavigators('google-chrome', 'ctrl+F5') + + def chromium(self): + # need to force ctrl+F5 here + self.SendKeyToAllWebkitBasedNavigators('chromium-browser', 'ctrl+F5') + + def konqueror(self): + # need to force ctrl+F5 here + self.SendKeyToAllWebkitBasedNavigators('konqueror', 'ctrl+F5') + + def midori(self): + self.SendKeyToAllWindows('midori', 'F5') + + def palemoon(self): + # need to force ctrl+F5 here + self.SendKeyToAllWindows('pale moon', 'F5') + + def qupzilla(self): + # need to force ctrl+F5 here + self.SendKeyToAllWebkitBasedNavigators('qupzilla', 'ctrl+F5') def iron(self): pass @@ -24,30 +41,119 @@ def safari64(self): # except NotImplemented("Safari64 support not implemented yet.") def firefox(self): - self.SendKeysToAllWindows('firefox', 'F5') + self.SendKeysToAllNamedWindows('firefox', 'F5') + + def nightly(self): + self.SendKeysToAllNamedWindows('nightly', 'F5') + + def vivaldi(self): + # need to force ctrl+F5 here + self.SendKeyToAllWebkitBasedNavigators('vivaldi', 'ctrl+F5') def opera(self): - pass - # except NotImplemented("Opera support not implemented yet.") + # need to force ctrl+F5 here + self.SendKeyToAllWebkitBasedNavigators('opera', 'ctrl+F5') def ie(self): pass # except NotImplemented("IE support not implemented yet.") - def SendKeysToAllWindows(self, cls, key): - "Sends the keystroke to all windows whose title matches the regex" + def custom(self, customWindow, customCommand): + customCommand = customCommand if customCommand else 'ctrl+R' + # Use the safer method + self.SendKeyToAllWebkitBasedNavigators(customWindow, customCommand) + + def getDesktop(self): + '''This method is here for compatibilty purpose + because sometime xdotool would throw + XGetWindowProperty[_NET_WM_DESKTOP] failed (code=1)''' + cmd = ['xdotool', 'get_desktop'] + try: + process = Popen(cmd, stdout=PIPE) + out, err = process.communicate() + return out.decode(encoding='UTF-8') + except Exception: + self.print_error(cmd) + return False + + def SendKeyToAllWebkitBasedNavigators(self, cls, key): + cmd = ['xdotool', 'search', + '--desktop', self.getDesktop(), + '--onlyvisible', + '--class', cls, + 'windowactivate', 'key', key] - cmd = ['xdotool', 'search', '--sync', '--onlyvisible', '--class', cls, 'windowfocus', 'key', key] + if self.activate_browser: + cmd += ['windowactivate'] + else: + # trick to bring sublime text back to front + # this avoids the webkit bug where you have + # to activatewindow before inputing key + call(['subl']) + + try: + call(cmd) + except Exception: + self.print_error(cmd) + + def SendKeyToAllWindows(self, cls, key): + cmd = ['xdotool', 'search', + '--desktop', self.getDesktop(), + '--onlyvisible', + '--class', cls, + 'key', key] if self.activate_browser: cmd += ['windowactivate'] - status_code = call(cmd) + try: + call(cmd) + except Exception: + self.print_error(cmd) + + def SendKeysToAllNamedWindows(self, cls, key): + "Sends the keystroke to all windows whose title matches the regex" + + cmd = ['wmctrl', '-l'] + try: + process = Popen(cmd, stdout=PIPE) + out, err = process.communicate() + except Exception: + self.print_error(cmd) + return + + process = Popen(['grep', '-ie', + '[-]\?[a-z0-9 ]*%s[a-z0-9 ]*$' % cls], + stdout=PIPE, stdin=PIPE) + process.stdin.write(out) + out, err = process.communicate() + + wID = "" + try: + wID = out.split()[0].decode(encoding='UTF-8') + except Exception: + # no window found + return + + cmd = ['xdotool', 'key', '--window', wID, key] + try: + call(cmd) + except Exception: + self.print_error(cmd) + return + + if self.activate_browser: + cmd = ['xdotool', 'windowactivate', wID] + try: + call(cmd) + except Exception: + self.print_error(cmd) + return - if status_code != 0: - sublime.error_message( - 'Browser Refresh cannot execute the specified program.\n\n' - '%s\n\n' - 'If program \'xdotool\' is currently not installed ' - 'you can install it by typing:\n\n' - 'sudo apt-get install xdotool' % " ".join(cmd)) + def print_error(prog, cmd): + sublime.error_message( + 'Browser Refresh cannot execute the specified program.\n\n' + '%s\n\n' + 'If program \'%s\' is currently not installed ' + 'you can install it by typing:\n\n' + 'sudo apt-get install %s' % (' '.join(cmd), cmd[0], cmd[0]))