Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #browser.py
- #! /usr/bin/env python
- # -*- coding: utf-8 -*-
- # Copyright (C) 2011 ~ 2014 Andy Stewart
- #
- # Author: Andy Stewart <lazycat.manatee@gmail.com>
- # Maintainer: Andy Stewart <lazycat.manatee@gmail.com>
- #
- # This program is free software: you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation, either version 3 of the License, or
- # any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with this program. If not, see <http://www.gnu.org/licenses/>.
- import os
- from PyQt5 import QtCore
- from PyQt5.QtNetwork import QNetworkCookieJar, QNetworkCookie
- from PyQt5.QtCore import QCoreApplication, QEvent
- from PyQt5.QtNetwork import QNetworkProxy
- if os.name == 'posix':
- QCoreApplication.setAttribute(QtCore.Qt.AA_X11InitThreads, True)
- from PyQt5.QtWebKitWidgets import QWebView, QWebPage
- from PyQt5.QtWebKit import QWebSettings
- from PyQt5.QtWidgets import QApplication
- from PyQt5.QtCore import QUrl, Qt
- from PyQt5 import QtGui
- import time
- import os
- from epc.server import ThreadingEPCServer
- import threading
- from PyQt5.QtWidgets import QWidget
- from PyQt5.QtGui import QPainter, QImage
- import functools
- from utils import get_parent_dir
- from xutils import get_xlib_display, grab_focus, ActiveWindowWatcher, get_parent_window_id
- from send_key import send_string
- class postGui(QtCore.QObject):
- throughThread = QtCore.pyqtSignal(object, object)
- def __init__(self, inclass=True):
- super(postGui, self).__init__()
- self.throughThread.connect(self.onSignalReceived)
- self.inclass = inclass
- def __call__(self, func):
- self._func = func
- @functools.wraps(func)
- def objCall(*args, **kwargs):
- self.emitSignal(args, kwargs)
- return objCall
- def emitSignal(self, args, kwargs):
- self.throughThread.emit(args, kwargs)
- def onSignalReceived(self, args, kwargs):
- if self.inclass:
- obj, args = args[0], args[1:]
- self._func(obj, *args, **kwargs)
- else:
- self._func(*args, **kwargs)
- class WebPage(QWebPage):
- def __init__(self):
- super(WebPage, self).__init__()
- def acceptNavigationRequest(self, frame, request, type):
- # Handle myself if got user event.
- if type == QWebPage.NavigationTypeLinkClicked:
- if self.view().press_ctrl_flag:
- call_method("open-url", [request.url().toString()])
- else:
- self.view().load(request.url())
- # Return False to stop default behavior.
- return False
- # Otherwise, use default behavior.
- return QWebPage.acceptNavigationRequest(self, frame, request, type)
- def javaScriptConsoleMessage(self, msg, lineNumber, sourceID):
- global print_console_info
- if print_console_info:
- call_message("JsConsole(%s:%d): %s" % (sourceID, lineNumber, msg))
- class BrowserBuffer(QWebView):
- redrawScreenshot = QtCore.pyqtSignal(object)
- updateProgress = QtCore.pyqtSignal()
- def __init__(self, buffer_id, buffer_width, buffer_height):
- super(BrowserBuffer, self).__init__()
- self.buffer_id = buffer_id
- self.buffer_width = buffer_width
- self.buffer_height = buffer_height
- self.setPage(WebPage())
- self.page().mainFrame().setScrollBarPolicy(Qt.Horizontal, Qt.ScrollBarAlwaysOff)
- cookie_jar.restore_cookies()
- self.page().networkAccessManager().setCookieJar(cookie_jar)
- self.page().userAgentForUrl = self.customize_user_agent
- self.settings().setUserStyleSheetUrl(QUrl.fromLocalFile(os.path.join(get_parent_dir(__file__), "theme.css")))
- self.settings().setAttribute(QWebSettings.PluginsEnabled, True)
- self.settings().setAttribute(QWebSettings.JavascriptEnabled, True)
- self.settings().setAttribute(QWebSettings.JavascriptCanOpenWindows, True)
- self.settings().setFontFamily(QWebSettings.StandardFont, "Sans")
- self.adjust_size(self.buffer_width, self.buffer_height)
- self.view_dict = {}
- self.titleChanged.connect(self.change_title)
- self.press_ctrl_flag = False
- self.loading_flag = False
- self.loading_percent = 0
- self.loadFinished.connect(self.handle_load_finished)
- self.loadStarted.connect(self.handle_load_started)
- self.loadProgress.connect(self.handle_load_progress)
- def handle_load_started(self, *args):
- self.loading_flag = True
- self.loading_percent = 0
- self.updateProgress.emit()
- def handle_load_finished(self, *args):
- self.loading_flag = False
- self.loading_percent = 100
- self.updateProgress.emit()
- def handle_load_progress(self, percent):
- self.loading_flag = True
- self.loading_percent = percent
- self.updateProgress.emit()
- def customize_user_agent(self, url):
- return "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.114 Safari/537.36"
- def change_title(self, title):
- call_method("change-buffer-title", [self.buffer_id, title])
- def eventFilter(self, obj, event):
- if event.type() in [QEvent.KeyPress, QEvent.KeyRelease,
- QEvent.MouseButtonPress, QEvent.MouseButtonRelease,
- QEvent.MouseMove, QEvent.MouseButtonDblClick, QEvent.Wheel,
- QEvent.InputMethod, QEvent.InputMethodQuery, QEvent.ShortcutOverride,
- QEvent.ActivationChange, QEvent.Enter, QEvent.WindowActivate,
- ]:
- QApplication.sendEvent(self, event)
- if event.type() == QEvent.KeyPress and event.key() == QtCore.Qt.Key_Control:
- self.press_ctrl_flag = True
- elif event.type() == QEvent.KeyRelease and event.key() == QtCore.Qt.Key_Control:
- self.press_ctrl_flag = False
- global emacs_xwindow_id
- xlib_display = get_xlib_display()
- xwindow = xlib_display.create_resource_object("window", emacs_xwindow_id)
- mask = []
- event_key = event.text()
- if event.modifiers() & QtCore.Qt.AltModifier == QtCore.Qt.AltModifier:
- mask.append("Alt")
- elif event.modifiers() & QtCore.Qt.ControlModifier == QtCore.Qt.ControlModifier:
- mask.append("Ctrl")
- elif event.modifiers() & QtCore.Qt.ShiftModifier == QtCore.Qt.ShiftModifier:
- mask.append("Shift")
- elif event.modifiers() & QtCore.Qt.MetaModifier == QtCore.Qt.MetaModifier:
- mask.append("Super")
- send_string(xwindow, event_key, mask, event.type() == QEvent.KeyPress)
- xlib_display.sync()
- else:
- if event.type() not in [12, 77]:
- call_method("%s %s" % (event.type(), event))
- return False
- def add_view(self, view_id, x, y, w, h):
- view = BrowserView(self, view_id)
- self.view_dict[view_id] = view
- self.update_view(view_id, x, y, w, h)
- view.show()
- def remove_view(self, view_id):
- if view_id in self.view_dict:
- self.view_dict[view_id].remove()
- self.view_dict.pop(view_id)
- def update_view(self, view_id, x, y, w, h):
- self.view_dict[view_id].moveresize(x, y, w, h)
- def remove_all_views(self):
- for view_id in self.view_dict.keys():
- self.remove_view(view_id)
- def adjust_size(self, width, height):
- self.buffer_width = width
- self.buffer_height = height
- self.resize(self.buffer_width, self.buffer_height)
- @postGui()
- def redraw(self):
- if len(self.view_dict) > 0:
- qimage = QImage(self.buffer_width, self.buffer_height, QImage.Format_ARGB32)
- self.render(qimage)
- self.redrawScreenshot.emit(qimage)
- @postGui()
- def open_url(self, url):
- self.load(QUrl(url))
- class BrowserView(QWidget):
- def __init__(self, browser_buffer, view_id):
- super(BrowserView, self).__init__()
- self.browser_buffer = browser_buffer
- self.view_id = view_id
- self.setWindowFlags(Qt.FramelessWindowHint)
- self.setAttribute(Qt.WA_TranslucentBackground, True)
- self.setContentsMargins(0, 0, 0, 0)
- self.browser_buffer.redrawScreenshot.connect(self.updateView)
- self.browser_buffer.updateProgress.connect(self.updateProgress)
- self.qimage = None
- self.installEventFilter(browser_buffer)
- def remove(self):
- self.browser_buffer.redrawScreenshot.disconnect(self.updateView)
- self.destroy()
- def paintEvent(self, event):
- painter = QPainter(self)
- if self.qimage:
- painter.drawImage(QtCore.QRect(0, 0, self.width(), self.height()), self.qimage)
- else:
- painter.setBrush(QtGui.QColor(255, 255, 255, 255))
- painter.drawRect(0, 0, self.browser_buffer.buffer_width, self.browser_buffer.buffer_height)
- if self.browser_buffer.loading_flag:
- painter.setPen(QtGui.QColor(10, 138, 255, 255))
- painter.setBrush(QtGui.QColor(10, 138, 255, 255))
- painter.drawRect(0, 0, self.browser_buffer.buffer_width * self.browser_buffer.loading_percent / 100, 1)
- painter.end()
- @postGui()
- def updateView(self, qimage):
- self.qimage = qimage
- self.update()
- @postGui()
- def updateProgress(self):
- self.update()
- def moveresize(self, x, y, w, h):
- self.resize(w, h)
- self.reparent(x, y)
- def adjust_size(self, x, y, w, h):
- self.moveresize(x, y, w, h)
- self.browser_buffer.adjust_size(w, h)
- def reparent(self, x, y):
- xlib_display = get_xlib_display()
- browser_xwindow_id = self.winId().__int__()
- browser_xwindow = xlib_display.create_resource_object("window", browser_xwindow_id)
- emacs_xwindow = xlib_display.create_resource_object("window", emacs_xwindow_id)
- browser_xwindow.reparent(emacs_xwindow, x, y)
- xlib_display.sync()
- class CookieJar(QNetworkCookieJar):
- def __init__(self, parent = None):
- QNetworkCookieJar.__init__(self, parent)
- self.cookie_path = os.path.expanduser("~/.emacs.d/deepin-emacs/webkit-cookies")
- def save_cookies(self):
- allCookies = QNetworkCookieJar.allCookies(self)
- cookie_dir = os.path.dirname(self.cookie_path)
- if not os.path.exists(cookie_dir):
- os.makedirs(cookie_dir)
- with open(self.cookie_path, 'w') as f:
- lines = ''
- for cookie in allCookies:
- lines = lines + cookie.toRawForm() + '\r\n'
- f.writelines(lines)
- def restore_cookies(self):
- if os.path.exists(self.cookie_path):
- with open(self.cookie_path, 'r') as f:
- lines = ''
- for line in f:
- lines = lines + line
- allCookies = QNetworkCookie.parseCookies(lines)
- QNetworkCookieJar.setAllCookies(self, allCookies)
- if __name__ == '__main__':
- import sys
- import signal
- app = QApplication(sys.argv)
- server = ThreadingEPCServer(('localhost', 0), log_traceback=True)
- server_thread = threading.Thread(target=server.serve_forever)
- server_thread.allow_reuse_address = True
- emacs_xwindow_id = 0
- buffer_dict = {}
- cookie_jar = CookieJar()
- print_console_info = False
- if len(sys.argv) >= 2 and sys.argv[1] == "--enable-proxy":
- QNetworkProxy.setApplicationProxy(QNetworkProxy(QNetworkProxy.Socks5Proxy, "127.0.0.1", 7070))
- def call_message(message):
- call_method("message", [message])
- def call_method(method_name, args):
- handler = server.clients[0]
- handler.call(method_name, args)
- def handle_active_window(active_window_id):
- global emacs_xwindow_id
- emacs_real_id = get_parent_window_id(emacs_xwindow_id)
- call_method("message", ["handle_active_window: %s %s %s" % (active_window_id, emacs_xwindow_id, emacs_real_id)])
- if active_window_id == emacs_real_id:
- call_method("focus-browser-view", [])
- @postGui(False)
- def init(emacs_xid):
- global emacs_xwindow_id
- emacs_xwindow_id = int(emacs_xid)
- # NOTE: every epc method must should wrap with postGui.
- # Because epc server is running in sub-thread.
- @postGui(False)
- def create_buffer(buffer_id, buffer_url, buffer_width, buffer_height):
- if not buffer_id in buffer_dict:
- buffer = BrowserBuffer(buffer_id, buffer_width, buffer_height)
- buffer.open_url(buffer_url)
- buffer_dict[buffer_id] = buffer
- @postGui(False)
- def remove_buffer(buffer_id):
- if buffer_id in buffer_dict:
- cookie_jar.save_cookies()
- buffer = buffer_dict[buffer_id]
- buffer.remove_all_views()
- buffer_dict.pop(buffer_id)
- buffer.destroy()
- call_message("Remove buffer %s" % buffer_id)
- @postGui(False)
- def adjust_size(buffer_id, w, h):
- if buffer_id in buffer_dict:
- buffer_dict[buffer_id].adjust_size(w, h)
- @postGui(False)
- def update_views(view_infos):
- buffer_view_dict = {}
- for view_info in view_infos:
- [buffer_id, x, y, w, h] = view_info
- view_id = "%s_%s" % (x, y)
- if buffer_id in buffer_dict:
- if not buffer_id in buffer_view_dict:
- buffer_view_dict[buffer_id] = {}
- buffer_view_dict[buffer_id][view_id] = (x, y, w, h)
- else:
- call_message("Buffer id %s is not exist!" % buffer_id)
- for buffer in buffer_dict.values():
- if buffer.buffer_id in buffer_view_dict:
- emacs_view_ids = buffer_view_dict[buffer.buffer_id].keys()
- buffer_view_ids = buffer.view_dict.keys()
- for emacs_view_id in emacs_view_ids:
- (x, y, w, h) = buffer_view_dict[buffer.buffer_id][emacs_view_id]
- # Update view.
- if emacs_view_id in buffer_view_ids:
- buffer.update_view(emacs_view_id, x, y, w, h)
- # Create view.
- else:
- buffer.add_view(emacs_view_id, x, y, w, h)
- for buffer_view_id in buffer_view_ids:
- # Remove view.
- if buffer_view_id not in emacs_view_ids:
- buffer.remove_view(buffer_view_id)
- else:
- buffer.remove_all_views()
- @postGui(False)
- def focus_view(buffer_id, x, y, w, h):
- if buffer_id in buffer_dict:
- buffer = buffer_dict[buffer_id]
- view_id = "%s_%s" % (x, y)
- if view_id in buffer.view_dict:
- view = buffer.view_dict[view_id]
- view_xwindow_id = view.winId().__int__()
- grab_focus(view_xwindow_id)
- def toggle_console_info():
- global print_console_info
- print_console_info = not print_console_info
- def update_buffer():
- while True:
- for buffer in buffer_dict.values():
- buffer.redraw()
- time.sleep(0.05)
- server_thread.start()
- server.print_port()
- server.register_function(init)
- server.register_function(create_buffer)
- server.register_function(remove_buffer)
- server.register_function(adjust_size)
- server.register_function(update_views)
- server.register_function(focus_view)
- server.register_function(toggle_console_info)
- threading.Thread(target=update_buffer).start()
- active_window_watcher = ActiveWindowWatcher()
- active_window_watcher.activeWindowChanged.connect(handle_active_window)
- active_window_watcher.start()
- signal.signal(signal.SIGINT, signal.SIG_DFL)
- sys.exit(app.exec_())
- ::-webkit-scrollbar {
- width: 12px;
- }
- ::-webkit-scrollbar-track {
- -webkit-box-shadow: inset 0 0 3px rgba(0,0,0,0.3);
- border-radius: 4px;
- }
- ::-webkit-scrollbar-thumb {
- border-radius: 4px;
- -webkit-box-shadow: inset 0 0 3px rgba(0,0,0,0.5);
- }
- #send_key.py
- #! /usr/bin/env python
- # -*- coding: utf-8 -*-
- # Copyright (C) 2011 ~ 2014 Andy Stewart
- #
- # Author: Andy Stewart <lazycat.manatee@gmail.com>
- # Maintainer: Andy Stewart <lazycat.manatee@gmail.com>
- #
- # This program is free software: you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation, either version 3 of the License, or
- # any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with this program. If not, see <http://www.gnu.org/licenses/>.
- import Xlib.display
- import Xlib.X
- import Xlib.XK
- import Xlib.protocol.event
- from xutils import get_xlib_display
- special_X_keysyms = {
- ' ' : "space",
- '\t' : "Tab",
- '\n' : "Return", # for some reason this needs to be cr, not lf
- '\r' : "Return",
- '\e' : "Escape",
- '!' : "exclam",
- '#' : "numbersign",
- '%' : "percent",
- '$' : "dollar",
- '&' : "ampersand",
- '"' : "quotedbl",
- '\'' : "apostrophe",
- '(' : "parenleft",
- ')' : "parenright",
- '*' : "asterisk",
- '=' : "equal",
- '+' : "plus",
- ',' : "comma",
- '-' : "minus",
- '.' : "period",
- '/' : "slash",
- ':' : "colon",
- ';' : "semicolon",
- '<' : "less",
- '>' : "greater",
- '?' : "question",
- '@' : "at",
- '[' : "bracketleft",
- ']' : "bracketright",
- '\\' : "backslash",
- '^' : "asciicircum",
- '_' : "underscore",
- '`' : "grave",
- '{' : "braceleft",
- '|' : "bar",
- '}' : "braceright",
- '~' : "asciitilde"
- }
- def get_keysym(ch):
- keysym = Xlib.XK.string_to_keysym(ch)
- if keysym == 0:
- # Unfortunately, although this works to get the correct keysym
- # i.e. keysym for '#' is returned as "numbersign"
- # the subsequent display.keysym_to_keycode("numbersign") is 0.
- if ch in special_X_keysyms:
- special = special_X_keysyms[ch]
- keysym = Xlib.XK.string_to_keysym(special)
- return keysym
- def send_string(window, str, modifiers, press=True):
- xlib_display = get_xlib_display()
- mask = 0
- for modifier in modifiers:
- if modifier == "Ctrl":
- mask |= Xlib.X.ControlMask
- elif modifier == "Alt":
- mask |= Xlib.X.Mod1Mask
- elif modifier == "Shift":
- mask |= Xlib.X.ShiftMask
- elif modifier == "Super":
- mask |= Xlib.X.Mod4Mask
- keycode = xlib_display.keysym_to_keycode(get_keysym(str))
- if press:
- event_type = Xlib.protocol.event.KeyPress
- else:
- event_type = Xlib.protocol.event.KeyRelease
- event = event_type(
- root=xlib_display.screen().root,
- window=window,
- child=Xlib.X.NONE,
- same_screen=1,
- root_x=0,
- root_y=0,
- event_x=0,
- event_y=0,
- state=mask,
- detail=keycode,
- time=Xlib.X.CurrentTime,
- )
- window.send_event(event, propagate=True)
- if __name__ == "__main__":
- xlib_display = get_xlib_display()
- xwindow = xlib_display.create_resource_object("window", 73400407)
- # send_string(xwindow, "x", ["Ctrl"], False)
- # send_string(xwindow, "x", ["Ctrl"], True)
- # send_string(xwindow, "h", [], False)
- # send_string(xwindow, "h", [], True)
- send_string(xwindow, "y", ["Super"], False)
- send_string(xwindow, "y", ["Super"], True)
- xlib_display.sync()
- #utils.py
- #! /usr/bin/env python
- # -*- coding: utf-8 -*-
- # Copyright (C) 2011 ~ 2014 Andy Stewart
- #
- # Author: Andy Stewart <lazycat.manatee@gmail.com>
- # Maintainer: Andy Stewart <lazycat.manatee@gmail.com>
- #
- # This program is free software: you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation, either version 3 of the License, or
- # any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with this program. If not, see <http://www.gnu.org/licenses/>.
- import os
- def get_parent_dir(filepath, level=1):
- '''
- Get parent directory with given return level.
- @param filepath: Filepath.
- @param level: Return level, default is 1
- @return: Return parent directory with given return level.
- '''
- parent_dir = os.path.realpath(filepath)
- while(level > 0):
- parent_dir = os.path.dirname(parent_dir)
- level -= 1
- return parent_dir
- ;;; webkit.el --- Running WebKit browser in Emacs
- ;; Filename: webkit.el
- ;; Description: Running WebKit browser in Emacs
- ;; Author: Andy Stewart <lazycat.manatee@gmail.com>
- ;; Maintainer: Andy Stewart <lazycat.manatee@gmail.com>
- ;; Copyright (C) 2014, Andy Stewart, all rights reserved.
- ;; Created: 2014-01-02 21:51:17
- ;; Version: 0.1
- ;; Last-Updated: 2014-01-02 21:51:17
- ;; By: Andy Stewart
- ;; URL: http://www.emacswiki.org/emacs/download/webkit.el
- ;; Keywords:
- ;; Compatibility: GNU Emacs 24.3.50.1
- ;;
- ;; Features that might be required by this library:
- ;;
- ;;
- ;;
- ;;; This file is NOT part of GNU Emacs
- ;;; License
- ;;
- ;; This program is free software; you can redistribute it and/or modify
- ;; it under the terms of the GNU General Public License as published by
- ;; the Free Software Foundation; either version 3, or (at your option)
- ;; any later version.
- ;; This program is distributed in the hope that it will be useful,
- ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
- ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ;; GNU General Public License for more details.
- ;; You should have received a copy of the GNU General Public License
- ;; along with this program; see the file COPYING. If not, write to
- ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth
- ;; Floor, Boston, MA 02110-1301, USA.
- ;;; Commentary:
- ;;
- ;; Running WebKit browser in Emacs
- ;;
- ;;; Installation:
- ;;
- ;; NOTE: just webkit.el can't work, you need install below depends first:
- ;; * PyQt5: http://www.riverbankcomputing.co.uk/software/pyqt/intro
- ;; * Python-Xlib: https://pypi.python.org/pypi/python-xlib
- ;; * Python-EPC: https://github.com/tkf/python-epc
- ;;
- ;; Detail description please look: http://www.emacswiki.org/emacs/WebKit
- ;;
- ;; Then put webkit.el to your load-path.
- ;; The load-path is usually ~/elisp/.
- ;; It's set in your ~/.emacs like this:
- ;; (add-to-list 'load-path (expand-file-name "~/elisp"))
- ;;
- ;; And the following to your ~/.emacs startup file.
- ;;
- ;; (require 'webkit)
- ;;
- ;; Quick start:
- ;;
- ;; M-x webkit-open-url
- ;;
- ;;; Customize:
- ;;
- ;;
- ;;
- ;; All of the above can customize by:
- ;; M-x customize-group RET webkit RET
- ;;
- ;;; Change log:
- ;;
- ;; 2014/01/02
- ;; * First released.
- ;;
- ;;; Acknowledgements:
- ;;
- ;;
- ;;
- ;;; TODO
- ;;
- ;;
- ;;
- ;;; Require
- (require 'epc)
- (when noninteractive
- (load "subr")
- (load "byte-run"))
- (eval-when-compile (require 'cl))
- ;;; Code:
- (defcustom webkit-mode-hook '()
- "WebKit mode hook."
- :type 'hook
- :group 'webkit-mode)
- (defvar webkit-mode-map
- (let ((map (make-sparse-keymap)))
- map)
- "Keymap used by `webkit-mode'.")
- (define-derived-mode webkit-mode text-mode "WebKit"
- (interactive)
- (kill-all-local-variables)
- (setq major-mode 'webkit-mode)
- (setq mode-name "WebKit")
- (set (make-local-variable 'buffer-id) (webkit-generate-id))
- (use-local-map webkit-mode-map)
- (run-hooks 'webkit-mode-hook))
- (defun webkit-get-window-allocation (&optional window)
- (let* ((window-edges (window-inside-pixel-edges window))
- (x (nth 0 window-edges))
- (y (nth 1 window-edges))
- (w (- (nth 2 window-edges) x))
- (h (- (nth 3 window-edges) y))
- )
- (list x y w h)))
- (defun webkit-get-emacs-xid ()
- (frame-parameter nil 'window-id))
- (random t)
- (defun webkit-generate-id ()
- (format "%04x%04x-%04x-%04x-%04x-%06x%06x"
- (random (expt 16 4))
- (random (expt 16 4))
- (random (expt 16 4))
- (random (expt 16 4))
- (random (expt 16 4))
- (random (expt 16 6))
- (random (expt 16 6)) ))
- (defvar webkit-enable-proxy-p nil)
- (defvar webkit-proxy-config-path "~/.emacs.d/deepin-emacs/webkit-proxy")
- (defun webkit-save-proxy-config ()
- (with-current-buffer (find-file-noselect webkit-proxy-config-path)
- (erase-buffer)
- (insert (prin1-to-string webkit-enable-proxy-p))
- (let ((delete-old-versions nil))
- (save-buffer 0))))
- (defun webkit-restore-proxy-config ()
- (if (file-exists-p webkit-proxy-config-path)
- (setq webkit-enable-proxy-p
- (read
- (with-temp-buffer
- (insert-file-contents webkit-proxy-config-path)
- (buffer-string))))))
- (webkit-restore-proxy-config)
- (defvar pyepc-file (expand-file-name "browser.py" (file-name-directory load-file-name)))
- (defvar pyepc-browser
- (let* ((browser
- (epc:start-epc (or (getenv "PYTHON") "python")
- (list pyepc-file
- (if webkit-enable-proxy-p "--enable-proxy" "--disable-proxy")))))
- (epc:call-deferred browser 'init (list (webkit-get-emacs-xid)))
- browser))
- (defvar webkit-buffer-dict (make-hash-table :test 'equal))
- (defvar webkit-history-urls-path "~/.emacs.d/deepin-emacs/webkit-history")
- (defvar webkit-history-urls (make-hash-table :test 'equal))
- (defvar webkit-title-length 30)
- (defvar webkit-tab-index 0)
- (defun webkit-create-buffer (url)
- (setq webkit-tab-index (+ webkit-tab-index 1))
- (let ((webkit-buffer (generate-new-buffer (concat (truncate-string-to-width url webkit-title-length)))))
- (with-current-buffer webkit-buffer
- (webkit-mode)
- (set (make-local-variable 'buffer-url) url)
- (puthash buffer-id webkit-buffer webkit-buffer-dict)
- )
- webkit-buffer))
- (defun webkit-get-url-name (url)
- (car (last (split-string url "://")))
- )
- (defun webkit-get-url-history (url-name)
- (if webkit-history-urls
- (gethash url-name webkit-history-urls)
- nil)
- )
- (defun webkit-change-buffer-title (id title)
- (let* ((buffer (gethash id webkit-buffer-dict)))
- (with-current-buffer buffer
- ;; Rename buffer title.
- (rename-buffer (truncate-string-to-width title webkit-title-length))
- ;; Record url title in history.
- (let* ((url-name (webkit-get-url-name buffer-url))
- (url-history (webkit-get-url-history url-name)))
- (if url-history
- (let ((url-number (car url-history))
- (url-title (cdr url-history)))
- (puthash url-name (list url-number title) webkit-history-urls)
- (webkit-save-history-urls))))
- )
- )
- )
- (defun webkit-delete-history-url (url-name)
- (let ((url-history (webkit-get-url-history url-name)))
- (when url-history
- (remhash url-name webkit-history-urls)
- (webkit-save-history-urls))))
- (defun webkit-clean-history ()
- (setq webkit-history-urls nil)
- (webkit-save-history-urls))
- (defun webkit-save-history-urls ()
- (with-current-buffer (find-file-noselect webkit-history-urls-path)
- (erase-buffer)
- (insert (prin1-to-string webkit-history-urls))
- (let ((delete-old-versions nil))
- (save-buffer 0))))
- (defun webkit-restore-history-urls ()
- (if (file-exists-p webkit-history-urls-path)
- (setq webkit-history-urls
- (read
- (with-temp-buffer
- (insert-file-contents webkit-history-urls-path)
- (buffer-string)))))
- ;; Init hash table if `webkit-history-urls' is nil.
- (unless webkit-history-urls
- (setq webkit-history-urls (make-hash-table :test 'equal)))
- )
- (webkit-restore-history-urls)
- (defun webkit-open-url (url)
- (interactive "sURL: ")
- (let* ((buffer (webkit-create-buffer url))
- (url-parts (split-string url "://"))
- )
- (unless (member (nth 0 url-parts) (list "http" "https" "ftp" "file"))
- (if (= (length url-parts) 1)
- (setq url (concat "http://" (nth 0 url-parts))))
- )
- (with-current-buffer buffer
- (let* ((window-allocation (webkit-get-window-allocation))
- (x (nth 0 window-allocation))
- (y (nth 1 window-allocation))
- (w (nth 2 window-allocation))
- (h (nth 3 window-allocation))
- (view-id (webkit-generate-id)))
- (epc:call-deferred pyepc-browser 'create_buffer (list buffer-id url w h))
- ))
- (switch-to-buffer buffer)
- ;; Record browse history.
- (let* ((url-name (webkit-get-url-name url))
- (url-history (webkit-get-url-history url-name)))
- (if url-history
- (let ((url-number (car url-history))
- (url-title (cdr url-history)))
- (puthash url-name (list (+ url-number 1) url-title) webkit-history-urls))
- (puthash url-name (list 1 url) webkit-history-urls))
- (webkit-save-history-urls))
- ))
- (defun webkit-monitor-window-change (&rest _)
- (let ((view-infos)
- (selected-buffer (window-buffer (selected-window))))
- (dolist (window (window-list))
- (let ((buffer (window-buffer window)))
- (with-current-buffer buffer
- (if (string= "webkit-mode" (format "%s" major-mode))
- (let* ((window-allocation (webkit-get-window-allocation window))
- (x (nth 0 window-allocation))
- (y (nth 1 window-allocation))
- (w (nth 2 window-allocation))
- (h (nth 3 window-allocation))
- )
- (add-to-list 'view-infos (list buffer-id x y w h))
- )))))
- (epc:call-deferred pyepc-browser 'update_views (list view-infos))
- (with-current-buffer selected-buffer
- (if (string= "webkit-mode" (format "%s" major-mode))
- (let* ((window-allocation (webkit-get-window-allocation (selected-window)))
- (w (nth 2 window-allocation))
- (h (nth 3 window-allocation))
- )
- (epc:call-deferred pyepc-browser 'adjust_size (list buffer-id w h))
- )))
- ))
- (defun webkit-monitor-buffer-kill ()
- (with-current-buffer (buffer-name)
- (if (string= "webkit-mode" (format "%s" major-mode))
- (progn
- (epc:call-deferred pyepc-browser 'remove_buffer (list buffer-id))
- (remhash buffer-id webkit-buffer-dict)))))
- (defun webkit-focus-browser-view ()
- (interactive)
- (with-current-buffer (current-buffer)
- (if (string= "webkit-mode" (format "%s" major-mode))
- (let* ((window-allocation (webkit-get-window-allocation (get-buffer-window (current-buffer))))
- (x (nth 0 window-allocation))
- (y (nth 1 window-allocation))
- (w (nth 2 window-allocation))
- (h (nth 3 window-allocation))
- )
- (epc:call-deferred pyepc-browser 'focus_view (list buffer-id x y w h))
- (message "Focus view: %S" buffer-id)
- )
- )))
- (defun webkit-toggle-console-info ()
- (interactive)
- (epc:call-deferred pyepc-browser 'toggle_console_info ()))
- (defun webkit-enable-proxy ()
- (interactive)
- (setq webkit-enable-proxy-p t)
- (webkit-save-proxy-config)
- (message "Enable webkit proxy, reboot emacs effective."))
- (defun webkit-disable-proxy ()
- (interactive)
- (setq webkit-enable-proxy-p nil)
- (webkit-save-proxy-config)
- (message "Disable webkit proxy, reboot emacs effective."))
- (defadvice switch-to-buffer (after webkit-switch-to-buffer-advice activate)
- (webkit-focus-browser-view))
- (defadvice other-window (after webkit-other-window-advice activate)
- (webkit-focus-browser-view))
- (add-hook 'window-configuration-change-hook #'webkit-monitor-window-change)
- (add-hook 'kill-buffer-hook #'webkit-monitor-buffer-kill)
- (epc:define-method pyepc-browser
- 'message
- (lambda (&rest args) (message "%S" args)))
- (epc:define-method pyepc-browser
- 'open-url
- (lambda (&rest args)
- (webkit-open-url (nth 0 args))
- ))
- (epc:define-method pyepc-browser
- 'change-buffer-title
- (lambda (&rest args)
- (webkit-change-buffer-title (nth 0 args) (nth 1 args))
- ))
- (epc:define-method pyepc-browser
- 'focus-browser-view
- (lambda (&rest args)
- (webkit-focus-browser-view)
- ))
- (setq browse-url-browser-function (lambda (url flag) (webkit-open-url url)))
- (provide 'webkit)
- ;;; webkit.el ends here
- #xutils.py
- #! /usr/bin/env python
- # -*- coding: utf-8 -*-
- # Copyright (C) 2011 ~ 2014 Andy Stewart
- #
- # Author: Andy Stewart <lazycat.manatee@gmail.com>
- # Maintainer: Andy Stewart <lazycat.manatee@gmail.com>
- #
- # This program is free software: you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation, either version 3 of the License, or
- # any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with this program. If not, see <http://www.gnu.org/licenses/>.
- from PyQt5 import QtCore
- xlib_display = None
- def get_xlib_display():
- global xlib_display
- if xlib_display == None:
- from Xlib import display
- xlib_display = display.Display()
- return xlib_display
- def grab_focus(window_id):
- global xlib_display
- from Xlib import X
- xwindow = xlib_display.create_resource_object("window", window_id)
- xwindow.set_input_focus(X.RevertToNone, X.CurrentTime)
- xwindow.configure(stack_mode=X.Above)
- xlib_display.sync()
- def get_parent_window_id(window_id):
- xlib_display = get_xlib_display()
- return xlib_display.create_resource_object("window", window_id).query_tree().parent.__window__()
- class ActiveWindowWatcher(QtCore.QThread):
- activeWindowChanged = QtCore.pyqtSignal(int)
- def __init__(self):
- super(ActiveWindowWatcher, self).__init__()
- xlib_display = get_xlib_display()
- from Xlib import X
- self.root = xlib_display.screen().root
- self.root.change_attributes(event_mask=(X.PropertyChangeMask))
- self.ACTIVE = xlib_display.intern_atom("_NET_ACTIVE_WINDOW")
- xlib_display.flush()
- self.active_window = self.root.get_full_property(self.ACTIVE, 0).value[0]
- self.do_active_window()
- def do_active_window(self):
- active = self.root.get_full_property(self.ACTIVE, 0).value[0]
- if active != self.active_window:
- self.active_window = active
- self.activeWindowChanged.emit(self.active_window.__int__())
- def run(self):
- xlib_display = get_xlib_display()
- import time
- from Xlib import X
- while 1:
- while xlib_display.pending_events():
- e = xlib_display.next_event()
- if e.type == X.PropertyNotify:
- self.do_active_window()
- time.sleep(0.1)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement