2
Copyright (C) 2009-2011 Lincoln de Sousa <lincoln@guake.org>
4
This program is free software; you can redistribute it and/or
5
modify it under the terms of the GNU General Public License as
6
published by the Free Software Foundation; either version 2 of the
7
License, or (at your option) any later version.
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
General Public License for more details.
14
You should have received a copy of the GNU General Public
15
License along with this program; if not, write to the
16
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17
Boston, MA 02110-1301 USA
19
from __future__ import absolute_import
20
from __future__ import division
21
from __future__ import print_function
23
from gi.repository import GConf
24
from gi.repository import Gdk
25
from gi.repository import GdkX11
26
from gi.repository import Gtk
27
from gi.repository import Pango
28
from gi.repository import Vte
30
from guake.common import clamp
31
from guake.globals import KEY
34
__all__ = ['Terminal', 'TerminalBox']
37
# regular expressions to highlight links in terminal. This code was
38
# lovely stolen from the great gnome-terminal project, thank you =)
39
USERCHARS = r"-[:alnum:]"
40
PASSCHARS = r"-[:alnum:],?;.:/!%$^*&~\"#'"
41
HOSTCHARS = r"-[:alnum:]"
42
HOST = r"[{hostchars}]+(\\.[{hostchars}]+)*".format(hostchars=HOSTCHARS)
43
PORT = r"(:[:digit:]{1,5})?"
44
PATHCHARS = r"-[:alnum:]_$.+!*(),;:@&=?/~#%"
45
SCHEME = r"(news:|telnet:|nntp:|file:/|https?:|ftps?:|webcal:)"
46
USER = r"[{userchars}]+(:[{passchars}]+)?".format(
49
URLPATH = r"/[{pathchars}]*[^]'.>) \t\r\n,\\\"]".format(pathchars=PATHCHARS)
50
TERMINAL_MATCH_TAGS = 'schema', 'http', 'email'
51
TERMINAL_MATCH_EXPRS = [
52
r"\<{scheme}//({user}@)?{host}{port}({urlpath})?\>/?".format(
59
r"\<(www|ftp)[{hostchars}]*\.{host}{port}({urlpath})?\>/?".format(
65
r"\<(mailto:)?[{userchars}][{userchars}.]*@[{hostchars}]+\.{host}\>".format(
72
# tuple (title/quick matcher/filename and line number extractor)
73
QUICK_OPEN_MATCHERS = [
75
r"^\s\sFile\s\".*\",\sline\s[0-9]+",
76
r"^\s\sFile\s\"(.*)\",\sline\s([0-9]+)"),
77
("line starts by 'Filename:line' pattern (GCC/make). File path should exists.",
78
r"^[a-zA-Z0-9\/\_\-\.\ ]+\.?[a-zA-Z0-9]+\:[0-9]+",
83
class Terminal(Vte.Terminal):
85
"""Just a Vte.Terminal with some properties already set.
89
super(Terminal, self).__init__()
90
self.configure_terminal()
92
self.connect('button-press-event', self.button_press)
93
self.matched_value = ''
94
self.font_scale_index = 0
96
def configure_terminal(self):
97
"""Sets all customized properties on the terminal
99
client = GConf.Client.get_default()
100
word_chars = client.get_string(KEY('/general/word_chars'))
101
self.set_word_chars(word_chars)
102
self.set_audible_bell(client.get_bool(KEY('/general/use_audible_bell')))
103
self.set_visible_bell(client.get_bool(KEY('/general/use_visible_bell')))
104
self.set_sensitive(True)
105
self.set_can_default(True)
106
self.set_can_focus(True)
108
def add_matches(self):
109
"""Adds all regular expressions declared in TERMINAL_MATCH_EXPRS
110
to the terminal to make vte highlight text that matches them.
112
# FIXME: match_add is deprecated we should use match_add_regex
113
# witch takes GRegex as parameter but first we need to find
114
# a way to construct GRegex objects (GLib.Regex)
116
# This is the error happening when trying to create a new
117
# GRegex: https://bugzilla.gnome.org/show_bug.cgi?id=647249
120
# for expr in TERMINAL_MATCH_EXPRS:
121
# tag = self.match_add_gregex(GLib.Regex(expr, 0))
122
# self.match_set_cursor_type(tag, Gdk.HAND2)
124
def button_press(self, terminal, event):
125
"""Handles the button press event in the terminal widget. If
126
any match string is caught, another aplication is open to
127
handle the matched resource uri.
129
self.matched_value = ''
130
matched_string = self.match_check(
131
int(event.x / self.get_char_width()),
132
int(event.y / self.get_char_height()))
133
value, tag = matched_string
135
if event.button == 1 \
136
and event.get_state() & Gdk.ModifierType.CONTROL_MASK \
138
if TERMINAL_MATCH_TAGS[tag] == 'schema':
139
# value here should not be changed, it is right and
142
elif TERMINAL_MATCH_TAGS[tag] == 'http':
143
value = 'http://%s' % value
144
elif TERMINAL_MATCH_TAGS[tag] == 'email':
145
value = 'mailto:%s' % value
147
Gtk.show_uri(self.get_screen(), value,
148
GdkX11.x11_get_server_time(self.get_window()))
149
elif event.button == 3 and matched_string:
150
self.matched_value = matched_string[0]
152
def set_font(self, font):
154
self.set_font_scale_index(0)
156
def set_font_scale_index(self, scale_index):
157
self.font_scale_index = clamp(scale_index, -6, 12)
159
font = Pango.FontDescription(self.font.to_string())
160
scale_factor = 2 ** (self.font_scale_index / 6)
161
new_size = int(scale_factor * font.get_size())
163
if font.get_size_is_absolute():
164
font.set_absolute_size(new_size)
166
font.set_size(new_size)
168
super(Terminal, self).set_font(font)
170
font_scale = property(
171
fset=set_font_scale_index,
172
fget=lambda self: self.font_scale_index
175
def increase_font_size(self):
178
def decrease_font_size(self):
182
class TerminalBox(Gtk.HBox):
184
"""A box to group the terminal and a scrollbar.
188
super(TerminalBox, self).__init__()
189
self.terminal = Terminal()
193
def add_terminal(self):
194
"""Packs the terminal widget.
196
self.pack_start(self.terminal, True, True, 0)
199
def add_scrollbar(self):
200
"""Packs the scrollbar.
202
adj = self.terminal.get_vadjustment()
203
scroll = Gtk.VScrollbar.new(adj)
204
scroll.set_no_show_all(True)
205
self.pack_start(scroll, False, False, 0)