Linux ns1.utparral.edu.mx 6.8.0-79-generic #79~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Fri Aug 15 16:54:53 UTC 2 x86_64
Apache/2.4.58 (Unix) OpenSSL/1.1.1w PHP/8.2.12 mod_perl/2.0.12 Perl/v5.34.1
: 10.10.1.9 | : 10.10.1.254
Cant Read [ /etc/named.conf ]
daemon
Terminal
AUTO ROOT
Adminer
Backdoor Destroyer
Linux Exploit
Lock Shell
Lock File
Create User
README
+ Create Folder
+ Create File
/
usr /
share /
org.gnome.Characters /
[ HOME SHELL ]
Name
Size
Permission
Action
gir-1.0
[ DIR ]
drwxr-xr-x
org.gnome.Characters
299
B
-rwxr-xr-x
org.gnome.Characters.BackgroundService
305
B
-rwxr-xr-x
org.gnome.Characters.BackgroundService.data.gresource
4.38
KB
-rw-r--r--
org.gnome.Characters.BackgroundService.src.gresource
17.76
KB
-rw-r--r--
org.gnome.Characters.data.gresource
113.39
KB
-rw-r--r--
org.gnome.Characters.src.gresource
81.17
KB
-rw-r--r--
Delete
Unzip
Zip
${this.title}
Close
Code Editor : org.gnome.Characters.src.gresource
GVariant � ( Ե ����� L � � �Xp� � v � 3! KFv� 3! L 8! X! {W�y X! v `! �1 KP� �1 L �1 �1 ��$0 �1 L �1 2 ���� 2 L 2 2 ��.G 2 v 2 $� �g� $� v 0� �� +Ka� �� v � � �(� � v � x� ���� x� v �� � �� � v � �D / characterDialog.js { // -*- Mode: js; indent-tabs-mode: nil; c-basic-offset: 4; tab-width: 4 -*- // // Copyright (C) 2014-2015 Daiki Ueno <dueno@src.gnome.org> // // 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 2 // of the License, 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; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. const {Gc, GLib, Gio,GObject,Gtk, Pango} = imports.gi; const Params = imports.params; const Util = imports.util; var CharacterDialog = GObject.registerClass({ Signals: { 'character-copied': { param_types: [ GObject.TYPE_STRING ] } }, Template: 'resource:///org/gnome/Characters/character.ui', InternalChildren: ['main-stack', 'character-stack', 'character-label', 'missing-label', 'detail-label', 'copy-button', 'copy-revealer', 'related-listbox'], }, class CharacterDialog extends Gtk.Dialog { _init(params) { const filtered = Params.filter(params, { character: null, fontDescription: null }); params = Params.fill(params, { use_header_bar: true, width_request: 400, height_request: 400 }); super._init(params); this._cancellable = new Gio.Cancellable(); this._copy_button.connect('clicked', () => this._copyCharacter()); this._related_listbox.connect('row-selected', (listBox, row) => this._handleRowSelected(listBox, row)); this._relatedButton = new Gtk.ToggleButton({ label: _("See Also") }); this.add_action_widget(this._relatedButton, Gtk.ResponseType.HELP); this._relatedButton.show(); this._relatedButton.connect('toggled', () => { if (this._main_stack.visible_child_name == 'character') this._main_stack.visible_child_name = 'related'; else this._main_stack.visible_child_name = 'character'; }); this._fontDescription = filtered.fontDescription; this._setCharacter(filtered.character); this._copyRevealerTimeoutId = 0; } _finishSearch(result) { let children = this._related_listbox.get_children(); for (let index in children) this._related_listbox.remove(children[index]); for (let index = 0; index < result.len; index++) { let uc = Gc.search_result_get(result, index); let name = Gc.character_name(uc); if (name == null) continue; let hbox = new Gtk.Box({ orientation: Gtk.Orientation.HORIZONTAL }); let characterLabel = new Gtk.Label({ label: uc, valign: Gtk.Align.CENTER, halign: Gtk.Align.CENTER, width_request: 45 }); characterLabel.get_style_context().add_class('character'); hbox.pack_start(characterLabel, false, false, 2); let nameLabel = new Gtk.Label({ label: Util.capitalize(name), halign: Gtk.Align.START, ellipsize: Pango.EllipsizeMode.END }); hbox.pack_start(nameLabel, true, true, 0); let row = new Gtk.ListBoxRow(); row._character = uc; row.add(hbox); row.show_all(); this._related_listbox.add(row); } this._relatedButton.visible = this._related_listbox.get_children().length > 0; } _setCharacter(uc) { this._character = uc; let codePoint = Util.toCodePoint(this._character); let codePointHex = codePoint.toString(16).toUpperCase(); let name = Gc.character_name(this._character); if (name != null) { name = Util.capitalize(name); } else { name = _("Unicode U+%04s").format(codePointHex); } let headerBar = this.get_header_bar(); headerBar.title = name; this._character_label.override_font(this._fontDescription); this._character_label.label = this._character; var pangoContext = this._character_label.get_pango_context(); var pangoLayout = Pango.Layout.new(pangoContext); pangoLayout.set_text(this._character, -1); if (pangoLayout.get_unknown_glyphs_count() == 0) { this._character_stack.visible_child_name = 'character'; } else { var fontFamily = this._fontDescription.get_family(); this._missing_label.label = // TRANSLATORS: the first variable is a character, the second is a font _("%s is not included in %s").format(name, fontFamily); this._character_stack.visible_child_name = 'missing'; } this._detail_label.label = _("Unicode U+%04s").format(codePointHex); this._cancellable.cancel(); this._cancellable.reset(); let criteria = Gc.SearchCriteria.new_related(this._character); let context = new Gc.SearchContext({ criteria: criteria }); context.search( -1, this._cancellable, (context, res) => { try { let result = context.search_finish(res); this._finishSearch(result); } catch (e) { log(`Failed to search related: ${e.message}`); } }); this._relatedButton.active = false; this._main_stack.visible_child_name = 'character'; this._main_stack.show_all(); } _hideCopyRevealer() { if (this._copyRevealerTimeoutId > 0) { GLib.source_remove(this._copyRevealerTimeoutId); this._copyRevealerTimeoutId = 0; this._copy_revealer.set_reveal_child(false); } } _clipboardOwnerChanged(clipboard) { let text = clipboard.wait_for_text(); if (text != this._character) this._hideCopyRevealer(); } _copyCharacter() { if (this._clipboard == null) { this._clipboard = Gc.gtk_clipboard_get(); let clipboardOwnerChanged = this._clipboard.connect('owner-change', (clipboard) => this._clipboardOwnerChanged(clipboard)); this.connect('destroy', () => this._clipboard.disconnect(clipboardOwnerChanged)); } this._clipboard.set_text(this._character, -1); this.emit('character-copied', this._character); // Show a feedback message with a revealer. The message is // hidden after 2 seconds, or when another client set a // different text to clipboard. this._hideCopyRevealer(); this._copy_revealer.set_reveal_child(true); this._copyRevealerTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 2000, () => this._hideCopyRevealer()); this.connect('destroy', () => { if (this._copyRevealerTimeoutId > 0) GLib.source_remove(this._copyRevealerTimeoutId); }); } _handleRowSelected(listBox, row) { if (row != null) { this._setCharacter(row._character); let toplevel = this.get_transient_for(); let action = toplevel.lookup_action('character'); action.activate(new GLib.Variant('s', row._character)); } } }); (uuay)js/ main.js z // -*- Mode: js; indent-tabs-mode: nil; c-basic-offset: 4; tab-width: 4 -*- // // Copyright (c) 2013 Giovanni Campagna <scampa.giovanni@gmail.com> // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // * Neither the name of the GNOME Foundation nor the // names of its contributors may be used to endorse or promote products // derived from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. pkg.initGettext(); pkg.initFormat(); pkg.require({ 'Gdk': '3.0', 'Gio': '2.0', 'GLib': '2.0', 'GObject': '2.0', 'Gtk': '3.0', 'Handy': '1', }); const {GLib, Gio, GObject, Gtk, Handy} = imports.gi; const Util = imports.util; const Window = imports.window; var settings = null; var application_id = pkg.name; function initEnvironment() { window.getApp = function() { return Gio.Application.get_default(); }; } var MyApplication = GObject.registerClass({ },class MyApplication extends Gtk.Application { _init () { super._init({ application_id: application_id, flags: Gio.ApplicationFlags.FLAGS_NONE }); GLib.set_application_name(_('Characters')); } _onQuit () { this.quit(); } _onSearch (action, parameter) { const window = new Window.MainWindow({ application: this }); window.setSearchKeywords(parameter.get_strv()); window.show(); } vfunc_startup () { super.vfunc_startup(); let theme = Gtk.IconTheme.get_default(); theme.add_resource_path('/org/gnome/Characters/icons'); Util.loadStyleSheet('/org/gnome/Characters/application.css'); let styleManager = Handy.StyleManager.get_default(); styleManager.set_color_scheme(Handy.ColorScheme.PREFER_LIGHT); Util.initActions(this, [{ name: 'quit', activate: this._onQuit }, { name: 'search', activate: this._onSearch, parameter_type: new GLib.VariantType('as') }]); this.set_accels_for_action('app.quit', ['<Primary>q']); this.set_accels_for_action('win.find', ['<Primary>f']); this.set_accels_for_action('win.show-primary-menu', ['F10']); this.set_accels_for_action('win.show-help-overlay', ['<Primary>question']); settings = Util.getSettings('org.gnome.Characters', '/org/gnome/Characters/'); log("Characters Application started"); } vfunc_activate() { if (!this._appwindow) { this._appwindow = new Window.MainWindow({ application: this }); } Handy.init(); this._appwindow.present(); log("Characters Application activated"); } vfunc_shutdown() { log("Characters Application exiting"); super.vfunc_shutdown(); } }); function main(argv) { initEnvironment(); return (new MyApplication()).run(argv); } (uuay)org/ gnome/ Characters/ characterList.js�` // -*- Mode: js; indent-tabs-mode: nil; c-basic-offset: 4; tab-width: 4 -*- // // Copyright (C) 2014-2015 Daiki Ueno <dueno@src.gnome.org> // // 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 2 // of the License, 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; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. const Params = imports.params; const {Gc, Gdk, GLib, Gio,GObject,Gtk, Pango, PangoCairo, Handy} = imports.gi; const Cairo = imports.cairo; const Main = imports.main; const Util = imports.util; const BASELINE_OFFSET = 0.85; const CELLS_PER_ROW = 5; const NUM_ROWS = 5; const NUM_COLUMNS = 3; const CELL_SIZE = 50; function getCellSize(fontDescription) { if (fontDescription == null || fontDescription.get_size() == 0) return CELL_SIZE; return fontDescription.get_size() * 2 / Pango.SCALE; } const CharacterListRow = GObject.registerClass({ }, class CharacterListRow extends GObject.Object { _init(params) { const filtered = Params.filter(params, { characters: null, fontDescription: null, overlayFontDescription: null }); params = Params.fill(params, {}); super._init(params); this._characters = filtered.characters; this._fontDescription = filtered.fontDescription; this._overlayFontDescription = filtered.overlayFontDescription; this._styleManager = Handy.StyleManager.get_default(); } draw(cr, x, y, width, height, styleContext) { let layout = PangoCairo.create_layout(cr); layout.set_font_description(this._fontDescription); this._styleContext = styleContext; // Draw baseline. // FIXME: Pick the baseline color from CSS. let fg_color = this._styleContext.get_color(Gtk.StateFlags.NORMAL); cr.setSourceRGBA(114.0 / 255.0, 159.0 / 255.0, 207.0 / 255.0, 1.0); cr.setLineWidth(0.5); cr.moveTo(x, y + BASELINE_OFFSET * height); cr.relLineTo(width, 0); cr.stroke(); cr.setSourceRGBA(fg_color.red, fg_color.green, fg_color.blue, fg_color.alpha); // Draw characters. Do centering and attach to the baseline. let cellSize = getCellSize(this._fontDescription); for (let i in this._characters) { var cellRect = new Gdk.Rectangle({ x: x + cellSize * i, y: y, width: cellSize, height: cellSize }); if (Gc.character_is_invisible(this._characters[i])) { this._drawBoundingBox(cr, cellRect, this._characters[i]); this._drawCharacterName(cr, cellRect, this._characters[i]); } else { layout.set_text(this._characters[i], -1); if (layout.get_unknown_glyphs_count () == 0) { let layoutBaseline = layout.get_baseline(); let [logicalRect, inkRect] = layout.get_extents(); cr.moveTo(x + cellSize * i - logicalRect.x / Pango.SCALE + (cellSize - logicalRect.width / Pango.SCALE) / 2, y + BASELINE_OFFSET * height - layoutBaseline / Pango.SCALE); PangoCairo.show_layout(cr, layout); } else { this._drawBoundingBox(cr, cellRect, this._characters[i]); this._drawCharacterName(cr, cellRect, this._characters[i]); } } } } _computeBoundingBox(cr, cellRect, uc) { let layout = PangoCairo.create_layout(cr); layout.set_font_description(this._fontDescription); layout.set_text(uc, -1); let shapeRect; let layoutBaseline; if (layout.get_unknown_glyphs_count() == 0) { let [logicalRect, inkRect] = layout.get_extents(); layoutBaseline = layout.get_baseline(); shapeRect = inkRect; } else { // If the character cannot be rendered with the current // font settings, show a rectangle calculated from the // base glyphs ('AA'). if (this._baseGlyphRect == null) { layout.set_text('AA', -1); let [baseLogicalRect, baseInkRect] = layout.get_extents(); this._baseGlyphLayoutBaseline = layout.get_baseline(); this._baseGlyphRect = baseInkRect; } layoutBaseline = this._baseGlyphLayoutBaseline; shapeRect = new Pango.Rectangle({ x: this._baseGlyphRect.x, y: this._baseGlyphRect.y, width: this._baseGlyphRect.width, height: this._baseGlyphRect.height }); let characterWidth = Gc.character_width (uc); if (characterWidth > 1) shapeRect.width *= characterWidth; } shapeRect.x = cellRect.x - shapeRect.x / Pango.SCALE + (cellRect.width - shapeRect.width / Pango.SCALE) / 2; shapeRect.y = cellRect.y + BASELINE_OFFSET * cellRect.height - layoutBaseline / Pango.SCALE; shapeRect.width = shapeRect.width / Pango.SCALE; shapeRect.height = shapeRect.height / Pango.SCALE; return shapeRect; } _drawBoundingBox(cr, cellRect, uc) { cr.save(); cr.rectangle(cellRect.x, cellRect.y, cellRect.width, cellRect.height); cr.clip(); let layout = PangoCairo.create_layout(cr); layout.set_font_description(this._fontDescription); layout.set_text(uc, -1); let shapeRect = this._computeBoundingBox(cr, cellRect, uc); let borderWidth = 1; cr.rectangle(shapeRect.x - borderWidth * 2, shapeRect.y - borderWidth * 2, shapeRect.width + borderWidth * 2, shapeRect.height + borderWidth * 2); cr.setSourceRGBA(239.0 / 255.0, 239.0 / 255.0, 239.0 / 255.0, 1.0); cr.fill(); cr.restore(); } _drawCharacterName(cr, cellRect, uc) { cr.save(); cr.rectangle(cellRect.x, cellRect.y, cellRect.width, cellRect.height); cr.clip(); let layout = PangoCairo.create_layout(cr); layout.set_width(cellRect.width * Pango.SCALE * 0.8); layout.set_height(cellRect.height * Pango.SCALE * 0.8); layout.set_wrap(Pango.WrapMode.WORD); layout.set_ellipsize(Pango.EllipsizeMode.END); layout.set_alignment(Pango.Alignment.CENTER); layout.set_font_description(this._overlayFontDescription); let name = Gc.character_name(uc); let text = name == null ? _('Unassigned') : Util.capitalize(name); layout.set_text(text, -1); let [logicalRect, inkRect] = layout.get_extents(); cr.moveTo(cellRect.x - logicalRect.x / Pango.SCALE + (cellRect.width - logicalRect.width / Pango.SCALE) / 2, cellRect.y - logicalRect.y / Pango.SCALE + (cellRect.height - logicalRect.height / Pango.SCALE) / 2); let text_color; if (!this._styleManager.dark) { text_color = this._styleContext.get_color(Gtk.StateFlags.NORMAL); } else { text_color = this._styleContext.get_background_color(Gtk.StateFlags.NORMAL); } cr.setSourceRGBA(text_color.red, text_color.green, text_color.blue, text_color.alpha); PangoCairo.show_layout(cr, layout); cr.restore(); } }); const CharacterListWidget = GObject.registerClass({ Signals: { 'character-selected': { param_types: [ GObject.TYPE_STRING ] } }, }, class CharacterListWidget extends Gtk.DrawingArea { _init(params) { const filtered = Params.filter(params, { fontDescription: null, numRows: NUM_ROWS }); params = Params.fill(params, {}); super._init(params); const context = this.get_style_context(); context.add_class('character-list'); context.save(); this._cellsPerRow = CELLS_PER_ROW; this._fontDescription = filtered.fontDescription; this._numRows = filtered.numRows; this._characters = []; this._rows = []; this.add_events(Gdk.EventMask.BUTTON_PRESS_MASK | Gdk.EventMask.BUTTON_RELEASE_MASK); this._character = null; this.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, null, Gdk.DragAction.COPY); this.drag_source_add_text_targets(); } vfunc_drag_begin(context) { let cellSize = getCellSize(this._fontDescription); this._dragSurface = new Cairo.ImageSurface(Cairo.Format.ARGB32, cellSize, cellSize); let cr = new Cairo.Context(this._dragSurface); cr.setSourceRGBA(1.0, 1.0, 1.0, 1.0); cr.paint(); cr.setSourceRGBA(0.0, 0.0, 0.0, 1.0); let row = this._createCharacterListRow([this._character]); row.draw(cr, 0, 0, cellSize, cellSize, this.get_style_context()); Gtk.drag_set_icon_surface(context, this._dragSurface, 0, 0); } vfunc_drag_data_get(context, data, info, time) { if (this._character != null) data.set_text(this._character, -1); } vfunc_button_press_event(event) { let allocation = this.get_allocation(); let cellSize = getCellSize(this._fontDescription); let x = Math.floor(event.x / cellSize); let y = Math.floor(event.y / cellSize); let index = y * this._cellsPerRow + x; if (index < this._characters.length) this._character = this._characters[index]; else this._character = null; return false; } vfunc_button_release_event(event) { if (this._character) this.emit('character-selected', this._character); return false; } vfunc_get_request_mode() { return Gtk.SizeRequestMode.HEIGHT_FOR_WIDTH; } vfunc_get_preferred_height() { let [minWidth, natWidth] = this.vfunc_get_preferred_width(); return this.vfunc_get_preferred_height_for_width(minWidth); } vfunc_get_preferred_height_for_width(width) { let height = Math.max(this._rows.length, this._numRows) * getCellSize(this._fontDescription); return [height, height]; } vfunc_get_preferred_width() { return this.vfunc_get_preferred_width_for_height(0); } vfunc_get_preferred_width_for_height(height) { let cellSize = getCellSize(this._fontDescription); let minWidth = NUM_COLUMNS * cellSize; let natWidth = Math.max(this._cellsPerRow, NUM_COLUMNS) * cellSize; return [minWidth, natWidth]; } vfunc_size_allocate(allocation) { super.vfunc_size_allocate(allocation); let cellSize = getCellSize(this._fontDescription); let cellsPerRow = Math.floor(allocation.width / cellSize); if (cellsPerRow != this._cellsPerRow) { // Reflow if the number of cells per row has changed. this._cellsPerRow = cellsPerRow; this.setCharacters(this._characters); } } _createCharacterListRow(characters) { var context = this.get_pango_context(); var fontDescription = context.get_font_description(); fontDescription.set_size(fontDescription.get_size() * 0.8); let row = new CharacterListRow({ characters: characters, fontDescription: this._fontDescription, overlayFontDescription: fontDescription }); return row; } setFontDescription(fontDescription) { this._fontDescription = fontDescription; } setCharacters(characters) { this._rows = []; this._characters = characters; let start = 0, stop = 1; for (; stop <= characters.length; stop++) { if (stop % this._cellsPerRow == 0) { let rowCharacters = characters.slice(start, stop); let row = this._createCharacterListRow(rowCharacters); this._rows.push(row); start = stop; } } if (start != stop - 1) { let rowCharacters = characters.slice(start, stop); let row = this._createCharacterListRow(rowCharacters); this._rows.push(row); } this.queue_resize(); this.queue_draw(); } vfunc_draw(cr) { // Clear the canvas. let context = this.get_style_context(); let fg = context.get_color(Gtk.StateFlags.NORMAL); let bg = context.get_background_color(Gtk.StateFlags.NORMAL); cr.setSourceRGBA(bg.red, bg.green, bg.blue, bg.alpha); cr.paint(); cr.setSourceRGBA(fg.red, fg.green, fg.blue, fg.alpha); // Use device coordinates directly, since PangoCairo doesn't // work well with scaled matrix: // https://bugzilla.gnome.org/show_bug.cgi?id=700592 let allocation = this.get_allocation(); // Redraw rows within the clipped region. let [x1, y1, x2, y2] = cr.clipExtents(); let cellSize = getCellSize(this._fontDescription); let start = Math.max(0, Math.floor(y1 / cellSize)); let end = Math.min(this._rows.length, Math.ceil(y2 / cellSize)); for (let index = start; index < end; index++) { this._rows[index].draw(cr, 0, index * cellSize, allocation.width, cellSize, context); } } }); const MAX_SEARCH_RESULTS = 100; var FontFilter = GObject.registerClass({ Properties: { 'font': GObject.ParamSpec.string( 'font', '', '', GObject.ParamFlags.READABLE | GObject.ParamFlags.WRITABLE, 'Cantarell 50') }, Signals: { 'filter-set': { param_types: [] } }, }, class FontFilter extends GObject.Object { get font() { return this._font; } set font(v) { let fontDescription = Pango.FontDescription.from_string(v); if (fontDescription.get_size() == 0) fontDescription.set_size(CELL_SIZE * Pango.SCALE); if (this._fontDescription && fontDescription.equal(this._fontDescription)) return; this._font = v; this._fontDescription = fontDescription; } get fontDescription() { if (this._filterFontDescription) return this._filterFontDescription; return this._fontDescription; } _init(params) { params = Params.fill(params, {}); super._init(params); this._fontDescription = null; this._filterFontDescription = null; Main.settings.bind('font', this, 'font', Gio.SettingsBindFlags.DEFAULT); } setFilterFont(v) { let fontDescription; if (v == null) { fontDescription = null; } else { fontDescription = Pango.FontDescription.from_string(v); fontDescription.set_size(this._fontDescription.get_size()); } if ((this._filterFontDescription != null && fontDescription == null) || (this._filterFontDescription == null && fontDescription != null) || (this._filterFontDescription != null && fontDescription != null && !fontDescription.equal(this._filterFontDescription))) { this._filterFontDescription = fontDescription; this.emit('filter-set'); } } apply(widget, characters) { let fontDescription = this._fontDescription; if (this._filterFontDescription) { let context = widget.get_pango_context(); let filterFont = context.load_font(this._filterFontDescription); let filteredCharacters = []; for (let index = 0; index < characters.length; index++) { let uc = characters[index]; if (Gc.pango_context_font_has_glyph(context, filterFont, uc)) filteredCharacters.push(uc); } characters = filteredCharacters; fontDescription = this._filterFontDescription; } return [fontDescription, characters]; } }); var CharacterListView = GObject.registerClass({ Template: 'resource:///org/gnome/Characters/characterlist.ui', InternalChildren: ['loading-spinner'], Signals: { 'character-selected': { param_types: [ GObject.TYPE_STRING ] } }, }, class CharacterListView extends Gtk.Stack { _init(params) { const filtered = Params.filter(params, { fontFilter: null, }); params = Params.fill(params, { hexpand: true, vexpand: true, transition_type: Gtk.StackTransitionType.CROSSFADE }); super._init(params); this._fontFilter = filtered.fontFilter; this._characterList = new CharacterListWidget({ hexpand: true, vexpand: true, fontDescription: this._fontFilter.fontDescription }); this._characterList.connect('character-selected', (w, c) => this.emit('character-selected', c)); let scroll = new Gtk.ScrolledWindow({ hscrollbar_policy: Gtk.PolicyType.NEVER, visible: true }); scroll.add(this._characterList); let context = scroll.get_style_context(); context.add_class('character-list-scroll'); context.save(); this.add_named(scroll, 'character-list'); this.visible_child_name = 'character-list'; this._fontFilter.connect('filter-set', () => this._updateCharacterList()); this._characters = []; this._spinnerTimeoutId = 0; this._searchContext = null; this._cancellable = new Gio.Cancellable(); this._cancellable.connect(() => { this._stopSpinner(); this._searchContext = null; this._characters = []; this._updateCharacterList(); }); scroll.connect('edge-reached', (scrolled, pos) => this._onEdgeReached(scrolled, pos)); scroll.connect('size-allocate', (scrolled, allocation) => this._onSizeAllocate(scrolled, allocation)); } _startSpinner() { this._stopSpinner(); this._spinnerTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 1000, () => { this._loading_spinner.start(); this.visible_child_name = 'loading'; this.show_all(); }); } _stopSpinner() { if (this._spinnerTimeoutId > 0) { GLib.source_remove(this._spinnerTimeoutId); this._spinnerTimeoutId = 0; this._loading_spinner.stop(); } } _finishSearch(result) { this._stopSpinner(); let characters = Util.searchResultToArray(result); this.setCharacters(characters); } setCharacters(characters) { this._characters = characters; this._updateCharacterList(); } _updateCharacterList() { const [fontDescription, characters] = this._fontFilter.apply(this, this._characters); this._characterList.setFontDescription(fontDescription); this._characterList.setCharacters(characters); if (characters.length == 0) { this.visible_child_name = 'unavailable'; } else { this.visible_child_name = 'character-list'; } this.show_all(); } _maybeLoadMore() { if (this._searchContext != null && !this._searchContext.is_finished()) { this._searchWithContext(this._searchContext, MAX_SEARCH_RESULTS); } } _onEdgeReached(scrolled, pos) { if (pos == Gtk.PositionType.BOTTOM) { this._maybeLoadMore(); } } get initialSearchCount() { // Use our parents allocation; we aren't visible before we do the // initial search, so our allocation is 1x1 let allocation = this.get_parent().get_allocation(); // Sometimes more MAX_SEARCH_RESULTS are visible on screen // (eg. fullscreen at 1080p). We always present a over-full screen, // otherwise the lazy loading gets broken let cellSize = getCellSize(this._fontFilter.fontDescription); let cellsPerRow = Math.floor(allocation.width / cellSize); // Ensure the rows cause a scroll let heightInRows = Math.ceil((allocation.height + 1) / cellSize); return Math.max(MAX_SEARCH_RESULTS, heightInRows * cellsPerRow); } _onSizeAllocate(scrolled, allocation) { if (this._characters.length < this.initialSearchCount) { this._maybeLoadMore(); } } _addSearchResult(result) { const characters = Util.searchResultToArray(result); this.setCharacters(this._characters.concat(characters)); } _searchWithContext(context, count) { this._startSpinner(); context.search(count, this._cancellable, (context, res, user_data) => { this._stopSpinner(); try { let result = context.search_finish(res); this._addSearchResult(result); } catch (e) { log(`Failed to search: ${e.message}`); } }); } searchByCategory(category) { this._characters = []; if ('scripts' in category) { this.searchByScripts(category.scripts); return; } let criteria = Gc.SearchCriteria.new_category(category.category); this._searchContext = new Gc.SearchContext({ criteria: criteria }); this._searchWithContext(this._searchContext, this.initialSearchCount); } searchByKeywords(keywords) { const criteria = Gc.SearchCriteria.new_keywords(keywords); this._searchContext = new Gc.SearchContext({ criteria: criteria, flags: Gc.SearchFlag.WORD }); this._searchWithContext(this._searchContext, this.initialSearchCount); } searchByScripts(scripts) { var criteria = Gc.SearchCriteria.new_scripts(scripts); this._searchContext = new Gc.SearchContext({ criteria: criteria }); this._searchWithContext(this._searchContext, this.initialSearchCount); } cancelSearch() { this._cancellable.cancel(); this._cancellable.reset(); } }); var RecentCharacterListView = GObject.registerClass({ Signals: { 'character-selected': { param_types: [ GObject.TYPE_STRING ] }, }, }, class RecentCharacterListView extends Gtk.Bin { _init(params) { const filtered = Params.filter(params, { category: null, fontFilter: null }); params = Params.fill(params, { hexpand: true, vexpand: false }); super._init(params); this._fontFilter = filtered.fontFilter; this._characterList = new CharacterListWidget({ hexpand: true, vexpand: true, fontDescription: this._fontFilter.fontDescription, numRows: 0 }); this._characterList.connect('character-selected', (w, c) => this.emit('character-selected', c)); this.add(this._characterList); this._fontFilter.connect('filter-set', () => this._updateCharacterList()); this._category = filtered.category; this._characters = []; } setCharacters(characters) { const result = Gc.filter_characters(this._category, characters); this._characters = Util.searchResultToArray(result); this._updateCharacterList(); } _updateCharacterList() { const [fontDescription, characters] = this._fontFilter.apply(this, this._characters); this._characterList.setFontDescription(fontDescription); this._characterList.setCharacters(characters); this.show_all(); } }); (uuay)params.js � // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // Params: // // A set of convenience functions for dealing with pseudo-keyword // arguments. // // Examples: // // A function with complex arguments // function myFunction(params) { // params = Params.parse(params, { myFlags: Flags.NONE, // anInt: 42, // aString: 'hello, world!', // }); // ... params.anInt, params.myFlags, params.aString ... // } // myFunction({ anInt: -1 }); // // Extend a method to allow more params in a subclass // The superclass can safely use Params.parse(), it won't see // the extensions. // const MyClass = new Lang.Class({ // ... // method: function(params) { // let mine = Params.filter(params, { anInt: 42 }); // this.parent(params); // ... mine.anInt ... // } // }); // parse: // @params: caller-provided parameter object, or %null // @defaults: function-provided defaults object // // Examines @params and fills in default values from @defaults for // any properties in @defaults that don't appear in @params. // This function will throw a Error if @params contains a property // that is not recognized. Use fill() or filter() if you don't // want that. // // If @params is %null, this returns the values from @defaults. // // Return value: a new object, containing the merged parameters from // @params and @defaults function parse(params, defaults) { let ret = {}, prop; params = params || {}; for (prop in params) { if (!(prop in defaults)) throw new Error('Unrecognized parameter "' + prop + '"'); ret[prop] = params[prop]; } for (prop in defaults) { if (!(prop in params)) ret[prop] = defaults[prop]; } return ret; } // fill: // @params: caller-provided parameter object, or %null // @defaults: function-provided defaults object // // Examines @params and fills in default values from @defaults // for any properties in @defaults that don't appear in @params. // // Differently from parse(), this function does not throw for // unrecognized parameters. // // Return value: a new object, containing the merged parameters from // @params and @defaults function fill(params, defaults) { let ret = {}, prop; params = params || {}; for (prop in params) ret[prop] = params[prop]; for (prop in defaults) { if (!(prop in ret)) ret[prop] = defaults[prop]; } return ret; } // filter: // @params: caller-provided parameter object, or %null // @defaults: function-provided defaults object // // Examines @params and returns an object containing the // same properties as @defaults, but with values taken from // @params where available. // Then it removes from @params all matched properties. // // This is similar to parse(), but it accepts unknown properties // and modifies @params for known ones. // // If @params is %null, this returns the values from @defaults. // // Return value: a new object, containing the merged parameters from // @params and @defaults function filter(params, defaults) { let ret = {}, prop; params = params || {}; for (prop in defaults) { if (!(prop in params)) ret[prop] = defaults[prop]; } for (prop in params) { if (prop in defaults) { ret[prop] = params[prop]; delete params[prop]; } } return ret; } (uuay)menu.js � // -*- Mode: js; indent-tabs-mode: nil; c-basic-offset: 4; tab-width: 4 -*- // // Copyright (C) 2015 Daiki Ueno <dueno@src.gnome.org> // // 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 2 // of the License, 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; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. const {GLib, GObject, Gtk} = imports.gi; const Params = imports.params; var MenuPopover = GObject.registerClass({ Template: 'resource:///org/gnome/Characters/menu.ui', InternalChildren: ['search-entry', 'font-listbox'], }, class MenuPopover extends Gtk.Popover { _createFontListRow(title, family) { const row = new Gtk.ListBoxRow({ visible: true }); row.get_style_context().add_class('font'); row._family = family; let label = new Gtk.Label({ label: title, visible: true, halign: Gtk.Align.START }); label.get_style_context().add_class('font-label'); row.add(label); return row; } _init(params) { params = Params.fill(params, {}); super._init(params); let row = this._createFontListRow(_("None"), 'None'); this._font_listbox.add(row); let context = this.get_pango_context(); let families = context.list_families(); families = families.sort(function(a, b) { return a.get_name().localeCompare(b.get_name()); }); for (let index in families) { row = this._createFontListRow(families[index].get_name(), families[index].get_name()); this._font_listbox.add(row); } this._keywords = []; this._search_entry.connect('search-changed', (entry) => this._handleSearchChanged(entry)); this._font_listbox.connect('row-activated', (listBox, row) => this._handleRowActivated(listBox, row)); this._font_listbox.set_filter_func((row) => this._filterFunc(row)); // This silents warning at Characters exit about this widget being // visible but not mapped. Borrowed from Maps. this.connect('unmap', function(popover) { popover._font_listbox.unselect_all(); popover.hide(); }); } _handleSearchChanged(entry) { let text = entry.get_text().replace(/^\s+|\s+$/g, ''); let keywords = text == '' ? [] : text.split(/\s+/); this._keywords = keywords.map(x => x.toLowerCase()); this._font_listbox.invalidate_filter(); return true; } _handleRowActivated(listBox, row) { if (row != null) { let toplevel = this.get_toplevel(); let action = toplevel.lookup_action('filter-font'); action.activate(new GLib.Variant('s', row._family)); } } _filterFunc(row) { if (this._keywords.length == 0) return true; if (row._family == 'None') return true; let nameWords = row._family.split(/\s+/).map(x => x.toLowerCase()); return this._keywords.every(function(keyword, index, array) { return nameWords.some(function(nameWord, index, array) { return nameWord.indexOf(keyword) >= 0; }); }); } }); (uuay)util.jsP // -*- Mode: js; indent-tabs-mode: nil; c-basic-offset: 4; tab-width: 4 -*- // // Copyright (c) 2013 Giovanni Campagna <scampa.giovanni@gmail.com> // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // * Neither the name of the GNOME Foundation nor the // names of its contributors may be used to endorse or promote products // derived from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. const {Gc, Gdk, Gio, GObject, Gtk} = imports.gi; const Lang = imports.lang; const Params = imports.params; const System = imports.system; function loadUI(resourcePath, objects) { let ui = new Gtk.Builder(); if (objects) { for (let o in objects) ui.expose_object(o, objects[o]); } ui.add_from_resource(resourcePath); return ui; } function loadStyleSheet(resource) { let provider = new Gtk.CssProvider(); provider.load_from_file(Gio.File.new_for_uri('resource://' + resource)); Gtk.StyleContext.add_provider_for_screen(Gdk.Screen.get_default(), provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); } function initActions(actionMap, simpleActionEntries, context) { simpleActionEntries.forEach(function(entry) { let filtered = Params.filter(entry, { activate: null, state_changed: null, context: null }); let action = new Gio.SimpleAction(entry); let context = filtered.context || actionMap; if (filtered.activate) action.connect('activate', filtered.activate.bind(context)); if (filtered.state_changed) action.connect('state-changed', filtered.state_changed.bind(context)); actionMap.add_action(action); }); } function arrayEqual(one, two) { if (one.length != two.length) return false; for (let i = 0; i < one.length; i++) if (one[i] != two[i]) return false; return true; } function getSettings(schemaId, path) { const GioSSS = Gio.SettingsSchemaSource; let schemaSource; if (!pkg.moduledir.startsWith('resource://')) { // Running from the source tree schemaSource = GioSSS.new_from_directory(pkg.pkgdatadir, GioSSS.get_default(), false); } else { schemaSource = GioSSS.get_default(); } let schemaObj = schemaSource.lookup(schemaId, true); if (!schemaObj) { log('Missing GSettings schema ' + schemaId); System.exit(1); } if (path === undefined) return new Gio.Settings({ settings_schema: schemaObj }); else return new Gio.Settings({ settings_schema: schemaObj, path: path }); } function assertEqual(one, two) { if (one != two) throw Error('Assertion failed: ' + one + ' != ' + two); } function assertNotEqual(one, two) { if (one == two) throw Error('Assertion failed: ' + one + ' == ' + two); } function capitalizeWord(w) { if (w.length > 0) return w[0].toUpperCase() + w.slice(1).toLowerCase() return w; } function capitalize(s) { return s.split(/\s+/).map(function(w) { let acronyms = ["CJK"]; if (acronyms.indexOf(w) > -1) return w; let prefixes = ["IDEOGRAPH-", "SELECTOR-"]; for (let index in prefixes) { let prefix = prefixes[index]; if (w.startsWith(prefix)) return capitalizeWord(prefix) + w.slice(prefix.length); } return capitalizeWord(w); }).join(' '); } function toCodePoint(s) { let codePoint = s.charCodeAt(0); if (codePoint >= 0xD800 && codePoint <= 0xDBFF) { let high = codePoint; let low = s.charCodeAt(1); codePoint = 0x10000 + (high - 0xD800) * 0x400 + (low - 0xDC00); } return codePoint; } function searchResultToArray(result) { let characters = []; for (let index = 0; index < result.len; index++) { characters.push(Gc.search_result_get(result, index)); } return characters; } (uuay)categoryList.js u9 // -*- Mode: js; indent-tabs-mode: nil; c-basic-offset: 4; tab-width: 4 -*- // // Copyright (C) 2014-2017 Daiki Ueno <dueno@src.gnome.org> // // 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 2 // of the License, 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; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. const {Gc, GLib, GObject, Gtk, GnomeDesktop} = imports.gi; const Gettext = imports.gettext; const Params = imports.params; const Util = imports.util; const CategoryList = [ { name: 'emojis', category: Gc.Category.EMOJI, title: N_('Emojis'), icon_name: 'characters-emoji-smileys', }, { name: 'letters', category: Gc.Category.LETTER, title: N_('Letters & Symbols'), icon_name: 'characters-latin-symbolic', } ]; const LetterCategoryList = [ { name: 'punctuation', category: Gc.Category.LETTER_PUNCTUATION, title: N_('Punctuation'), icon_name: 'characters-punctuation-symbolic', }, { name: 'arrow', category: Gc.Category.LETTER_ARROW, title: N_('Arrows'), icon_name: 'characters-arrow-symbolic', }, { name: 'bullet', category: Gc.Category.LETTER_BULLET, title: N_('Bullets'), icon_name: 'characters-bullet-symbolic', }, { name: 'picture', category: Gc.Category.LETTER_PICTURE, title: N_('Pictures'), icon_name: 'characters-picture-symbolic', }, { name: 'currency', category: Gc.Category.LETTER_CURRENCY, title: N_('Currencies'), icon_name: 'characters-currency-symbolic', }, { name: 'math', category: Gc.Category.LETTER_MATH, title: N_('Math'), icon_name: 'characters-math-symbolic', }, { name: 'letters', category: Gc.Category.LETTER_LATIN, title: N_('Letters'), icon_name: 'characters-latin-symbolic', } ]; const EmojiCategoryList = [ { name: 'emoji-smileys', category: Gc.Category.EMOJI_SMILEYS, title: N_('Smileys & People'), icon_name: 'characters-emoji-smileys', }, { name: 'emoji-animals', category: Gc.Category.EMOJI_ANIMALS, title: N_('Animals & Nature'), icon_name: 'characters-emoji-animals', }, { name: 'emoji-food', category: Gc.Category.EMOJI_FOOD, title: N_('Food & Drink'), icon_name: 'characters-emoji-food', }, { name: 'emoji-activities', category: Gc.Category.EMOJI_ACTIVITIES, title: N_('Activities'), icon_name: 'characters-emoji-activities', }, { name: 'emoji-travel', category: Gc.Category.EMOJI_TRAVEL, title: N_('Travel & Places'), icon_name: 'characters-emoji-travel', }, { name: 'emoji-objects', category: Gc.Category.EMOJI_OBJECTS, title: N_('Objects'), icon_name: 'characters-emoji-objects', }, { name: 'emoji-symbols', category: Gc.Category.EMOJI_SYMBOLS, title: N_('Symbols'), icon_name: 'characters-emoji-symbols', }, { name: 'emoji-flags', category: Gc.Category.EMOJI_FLAGS, title: N_('Flags'), icon_name: 'characters-emoji-flags', } ]; const CategoryListRowWidget = GObject.registerClass({ }, class CategoryListRowWidget extends Gtk.ListBoxRow { _init (params, category) { params = Params.fill(params, {}); super._init(params); this.category = category; this.get_accessible().accessible_name = _('%s Category List Row').format(category.title); let hbox = new Gtk.Box({ orientation: Gtk.Orientation.HORIZONTAL }); this.add(hbox); let image = Gtk.Image.new_from_icon_name(category.icon_name, Gtk.IconSize.LARGE_TOOLBAR); image.get_style_context().add_class('category-icon'); hbox.pack_start(image, false, false, 2); let label = new Gtk.Label({ label: Gettext.gettext(category.title), halign: Gtk.Align.START }); label.get_style_context().add_class('category-label'); hbox.pack_start(label, true, true, 0); } }); const CategoryListWidget = GObject.registerClass({ }, class CategoryListWidget extends Gtk.ListBox { _init(params) { const filtered = Params.filter(params, { categoryList: null }); params = Params.fill(params, {}); super._init(params); this._categoryList = filtered.categoryList; this.populateCategoryList(); this._lastSelectedRow = null; for (let index in this._categoryList) { let category = this._categoryList[index]; let rowWidget = new CategoryListRowWidget({}, category); rowWidget.get_style_context().add_class('category'); this.add(rowWidget); } } vfunc_row_selected(row) { if (row != null && row.selectable) { let toplevel = row.get_toplevel(); let action = toplevel.lookup_action('category'); action.activate(new GLib.Variant('s', row.category.name)); this._lastSelectedRow = row; } } populateCategoryList() { } getCategoryList() { return this._categoryList; } getCategory(name) { for (let index in this._categoryList) { let category = this._categoryList[index]; if (category.name == name) return category; } return null; } restorePreviousSelection() { if (this._lastSelectedRow) { this.select_row(this._lastSelectedRow) } } unselect() { let selected = this.get_selected_row() if (selected) this.unselect_row(selected) } }); const LetterCategoryListWidget = GObject.registerClass({ }, class LetterCategoryListWidget extends CategoryListWidget { _finishListEngines(sources, bus, res) { try { let engines = bus.list_engines_async_finish(res); if (engines) { for (let j in engines) { let engine = engines[j]; let language = engine.get_language(); if (language != null) this._ibusLanguageList[engine.get_name()] = language; } } } catch (e) { log(`Failed to list engines: ${e.message}`); } this._finishBuildScriptList(sources); } _ensureIBusLanguageList(sources) { if (this._ibusLanguageList != null) return; this._ibusLanguageList = {}; // Don't assume IBus is always available. let ibus; try { ibus = imports.gi.IBus; } catch (e) { this._finishBuildScriptList(sources); return; } ibus.init(); let bus = new ibus.Bus(); if (bus.is_connected()) { bus.list_engines_async(-1, null, (sources, bus, res) => this._finishListEngines(sources, bus, res)); } else this._finishBuildScriptList(sources); } _finishBuildScriptList(sources) { let xkbInfo = new GnomeDesktop.XkbInfo(); let languages = []; for (let i in sources) { let [type, id] = sources[i]; switch (type) { case 'xkb': // FIXME: Remove this check once gnome-desktop gets the // support for that. if (xkbInfo.get_languages_for_layout) { languages = languages.concat( xkbInfo.get_languages_for_layout(id)); } break; case 'ibus': if (id in this._ibusLanguageList) languages.push(this._ibusLanguageList[id]); break; } } // Add current locale language to languages. languages.push(Gc.get_current_language()); let allScripts = []; for (let i in languages) { let language = GnomeDesktop.normalize_locale(languages[i]); if (language == null) continue; let scripts = Gc.get_scripts_for_language(languages[i]); for (let j in scripts) { let script = scripts[j]; // Exclude Latin and Han, since Latin is always added // at the top and Han contains too many characters. if (['Latin', 'Han'].indexOf(script) >= 0) continue; if (allScripts.indexOf(script) >= 0) continue; allScripts.push(script); } } allScripts.unshift('Latin'); let category = this.getCategory('letters'); category.scripts = allScripts; } populateCategoryList() { // Populate the "scripts" element of the "Letter" category // object, based on the current locale and the input-sources // settings. // // This works asynchronously, in the following call flow: // // _buildScriptList() // if an IBus input-source is configured: // _ensureIBusLanguageList() // ibus_bus_list_engines_async() // _finishListEngines() // _finishBuildScriptList() // else: // _finishBuildScriptList() // let settings = Util.getSettings('org.gnome.desktop.input-sources', '/org/gnome/desktop/input-sources/'); if (settings) { let sources = settings.get_value('sources').deep_unpack(); let hasIBus = sources.some(function(current, index, array) { return current[0] == 'ibus'; }); if (hasIBus) this._ensureIBusLanguageList(sources); else this._finishBuildScriptList(sources); } } }); const EmojiCategoryListWidget = GObject.registerClass({ }, class EmojiCategoryListWidget extends CategoryListWidget { _init(params) { params = Params.fill(params, {}); super._init(params); } getCategory(name) { return super.getCategory(name); } }); const RecentCategoryListWidget = GObject.registerClass({ }, class RecentCategoryListWidget extends CategoryListWidget { _init(params) { super._init(params); this.recentCategory = { name: 'recent', category: Gc.Category.NONE, title: N_('Recently Used'), icon_name: 'document-open-recent-symbolic', }; this.recentRow = new CategoryListRowWidget({}, this.recentCategory); this.recentRow.get_style_context().add_class('category'); this.recentRow.get_style_context().add_class('recent-category'); this.add(this.recentRow) } getCategory(name) { return this.recentCategory; } }); var CategoryListView = GObject.registerClass({ }, class CategoryListView extends Gtk.Box { _init(params) { params = Params.fill(params, { hexpand: true, vexpand: true, orientation: Gtk.Orientation.VERTICAL, }); this._lastSelectedList = null; super._init(params); this.get_style_context().add_class('categories-list'); this._recentCategoryList = new RecentCategoryListWidget(); this._recentCategoryList.connect('row-selected', (list, row) => { this._letterCategoryList.unselect(); this._emojiCategoryList.unselect(); this._lastSelectedList = list; list.select_row(row); }); this.add(this._recentCategoryList) this.add(new Gtk.Separator({orientation: Gtk.Orientation.HORIZONTAL})); let emojis_label = new Gtk.Label ({ label: CategoryList[0].title, halign: Gtk.Align.START, margin_top: 12, margin_start: 12, margin_bottom: 12, margin_end: 12, }); emojis_label.get_style_context().add_class("heading"); this.add(emojis_label); this._emojiCategoryList = new EmojiCategoryListWidget({ categoryList: EmojiCategoryList }); this._emojiCategoryList.connect('row-selected', (list, row) => { this._letterCategoryList.unselect(); this._recentCategoryList.unselect(); this._lastSelectedList = list; list.select_row(row); }); this.add(this._emojiCategoryList); let letters_label = new Gtk.Label ({ label: CategoryList[1].title, halign: Gtk.Align.START, margin_top: 12, margin_start: 12, margin_bottom: 12, margin_end: 12, }); letters_label.get_style_context().add_class("heading"); this.add(letters_label); this._letterCategoryList = new LetterCategoryListWidget({ categoryList: LetterCategoryList }); this._letterCategoryList.connect('row-selected', (list, row) => { this._emojiCategoryList.unselect(); this._recentCategoryList.unselect(); this._lastSelectedList = list; list.select_row(row); }); this.add(this._letterCategoryList); this._categoryList = CategoryList.slice(); } getCategoryByName(name) { switch (name) { case 'emojis': return this._emojiCategoryList case 'recent': return this._recentCategoryList default: return this._letterCategoryList } } getCategoryList() { return this._categoryList; } get selectedList() { return this._lastSelectedList } restorePreviousSelection() { if (this._lastSelectedList) { this._lastSelectedList.restorePreviousSelection() } } }); (uuay)window.js �E // -*- Mode: js; indent-tabs-mode: nil; c-basic-offset: 4; tab-width: 4 -*- // // Copyright (c) 2013 Giovanni Campagna <scampa.giovanni@gmail.com> // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // * Neither the name of the GNOME Foundation nor the // names of its contributors may be used to endorse or promote products // derived from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. const {Gio, GLib, GObject, Gtk, Handy } = imports.gi; const Params = imports.params; const CategoryList = imports.categoryList; const Character = imports.characterDialog; const CharacterList = imports.characterList; const Menu = imports.menu; const Gettext = imports.gettext; const Main = imports.main; const Util = imports.util; var MainWindow = GObject.registerClass({ Template: 'resource:///org/gnome/Characters/mainwindow.ui', InternalChildren: [ 'main-headerbar', 'search-active-button', 'search-bar', 'search-entry', 'back-button', 'menu-button', 'container', 'sidebar', 'leaflet' ], Properties: { 'search-active': GObject.ParamSpec.boolean( 'search-active', '', '', GObject.ParamFlags.READABLE | GObject.ParamFlags.WRITABLE, false) }, }, class MainWindow extends Handy.ApplicationWindow { _init(params) { params = Params.fill(params, { title: GLib.get_application_name() }); super._init(params); this._searchActive = false; this._searchKeywords = []; Util.initActions(this, [{ name: 'about', activate: this._about }, { name: 'search-active', activate: this._toggleSearch, parameter_type: new GLib.VariantType('b'), state: new GLib.Variant('b', false) }, { name: 'find', activate: this._find }, { name: 'category', activate: this._category, parameter_type: new GLib.VariantType('s'), state: new GLib.Variant('s', 'emoji-smileys') }, { name: 'character', activate: this._character, parameter_type: new GLib.VariantType('s') }, { name: 'filter-font', activate: this._filterFont, parameter_type: new GLib.VariantType('s') }, { name: 'show-primary-menu', activate: this._togglePrimaryMenu, state: new GLib.Variant('b', false), }]); this.bind_property('search-active', this._search_active_button, 'active', GObject.BindingFlags.SYNC_CREATE | GObject.BindingFlags.BIDIRECTIONAL); this.bind_property('search-active', this._search_bar, 'search-mode-enabled', GObject.BindingFlags.SYNC_CREATE | GObject.BindingFlags.BIDIRECTIONAL); this._search_bar.connect_entry(this._search_entry); this._search_entry.connect('search-changed', (entry) => this._handleSearchChanged(entry)); this._back_button.connect('clicked', () => { this._leaflet.navigate(Handy.NavigationDirection.BACK); }); this._menu_popover = new Menu.MenuPopover({}); this._menu_button.set_popover(this._menu_popover); this._categoryListView = new CategoryList.CategoryListView({ vexpand: true }); this._categoryListView.show_all(); let scroll = new Gtk.ScrolledWindow({ hscrollbar_policy: Gtk.PolicyType.NEVER, hexpand: false, visible: true, }); scroll.add(this._categoryListView); this._sidebar.add(scroll); this._mainView = new MainView({ categoryListView: this._categoryListView }); this._container.pack_start(this._mainView, true, true, 0); let builder = Gtk.Builder.new_from_resource('/org/gnome/Characters/shortcuts.ui'); let helpOverlay = builder.get_object("shortcuts"); this.set_help_overlay(helpOverlay); // Due to limitations of gobject-introspection wrt GdkEvent // and GdkEventKey, this needs to be a signal handler this.connect('key-press-event', (self, event) => this._handleKeyPress(self, event)); } vfunc_map() { super.vfunc_map(); this._selectFirstSubcategory(); } _togglePrimaryMenu(action) { let state = action.get_state().get_boolean(); action.set_state(GLib.Variant.new_boolean(!state)); } // Select the first subcategory which contains at least one character. _selectFirstSubcategory() { let categoryList; if (this._mainView.recentCharacters.length !== 0) { categoryList = this._categoryListView.getCategoryByName('recent'); } else { categoryList = this._categoryListView.getCategoryByName('emojis'); } categoryList.select_row(categoryList.get_row_at_index(0)); } get search_active() { return this._searchActive; } set search_active(v) { if (this._searchActive == v) return; this._searchActive = v; if (this._searchActive) { let categoryList = this._categoryListView.selectedList; categoryList.unselect_all(); this._updateTitle(_("Search Result")); } else { this._categoryListView.restorePreviousSelection(); } this.notify('search-active'); } _handleSearchChanged(entry) { const text = entry.get_text().replace(/^\s+|\s+$/g, ''); let keywords = text == '' ? [] : text.split(/\s+/); keywords = keywords.map(x => x.toUpperCase()); if (keywords != this._searchKeywords) { this._mainView.cancelSearch(); this._searchKeywords = keywords; if (this._searchKeywords.length > 0) this._mainView.searchByKeywords(this._searchKeywords); } return true; } _handleKeyPress(self, event) { if (this._menu_popover.visible) return false; return this._search_bar.handle_event(event); } _about() { const aboutDialog = new Gtk.AboutDialog( { artists: [ 'Allan Day <allanpday@gmail.com>', 'Jakub Steiner <jimmac@gmail.com>' ], authors: [ 'Daiki Ueno <dueno@src.gnome.org>', 'Giovanni Campagna <scampa.giovanni@gmail.com>' ], // TRANSLATORS: put your names here, one name per line. translator_credits: _("translator-credits"), program_name: _("GNOME Characters"), comments: _("Character Map"), copyright: 'Copyright 2014-2018 Daiki Ueno', license_type: Gtk.License.GPL_2_0, logo_icon_name: Main.application_id, version: pkg.version, website: 'https://wiki.gnome.org/Apps/Characters', wrap_license: true, modal: true, transient_for: this }); aboutDialog.show(); aboutDialog.connect('response', function() { aboutDialog.destroy(); }); } _updateTitle(title) { if (this._mainView.filterFontFamily) { this._main_headerbar.title = _("%s (%s only)").format(Gettext.gettext(title), this._mainView.filterFontFamily); } else { this._main_headerbar.title = Gettext.gettext(title); } } _category(action, v) { this.search_active = false; let [name, length] = v.get_string(); let categoryName; if(name.startsWith("emoji")) { categoryName = "emojis"; } else if(name === "recent") { categoryName = "recent"; } else { categoryName = "letters"; } let categoryList = this._categoryListView.getCategoryByName(categoryName); let category = categoryList.getCategory(name); if (category) { this._mainView.setPage(category); this._updateTitle(category.title); this._leaflet.navigate(Handy.NavigationDirection.FORWARD); } } _character(action, v) { const [uc, length] = v.get_string(); this._mainView.addToRecent(uc); } _filterFont(action, v) { let [family, length] = v.get_string(); if (family == 'None') family = null; this._mainView.filterFontFamily = family; this._updateTitle(this._mainView.visible_child.title); this._menu_popover.hide(); } _find() { this.search_active = !this.search_active; } setSearchKeywords(keywords) { this.search_active = keywords.length > 0; this._search_entry.set_text(keywords.join(' ')); } }); const MainView = GObject.registerClass({ Template: 'resource:///org/gnome/Characters/mainview.ui', Properties: { 'max-recent-characters': GObject.ParamSpec.uint( 'max-recent-characters', '', '', GObject.ParamFlags.READABLE | GObject.ParamFlags.WRITABLE, 0, GLib.MAXUINT32, 100) }, }, class MainView extends Gtk.Stack { get max_recent_characters() { return this._maxRecentCharacters; } set max_recent_characters(v) { this._maxRecentCharacters = v; if (this.recentCharacters.length > this._maxRecentCharacters) this.recentCharacters = this.recentCharacters.slice( 0, this._maxRecentCharacters); } get filterFontFamily() { return this._filterFontFamily; } set filterFontFamily(family) { this._filterFontFamily = family; this._fontFilter.setFilterFont(this._filterFontFamily); } _init(params) { const filtered = Params.filter(params, { categoryListView: null }); params = Params.fill(params, { hexpand: true, vexpand: true, transition_type: Gtk.StackTransitionType.CROSSFADE }); super._init(params); this._fontFilter = new CharacterList.FontFilter({}); this._filterFontFamily = null; this._characterLists = {}; this._recentCharacterLists = {}; this._categoryListView = filtered.categoryListView; let characterList; let categories = this._categoryListView.getCategoryList(); let recentBox = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL, hexpand: true, vexpand: false }); for (let i in categories) { let category = categories[i]; let categoryList = this._categoryListView.getCategoryByName(category.name); let subcategories = categoryList.getCategoryList(); for (let j in subcategories) { let subcategory = subcategories[j]; characterList = this._createCharacterList( subcategory.name, _('%s Character List').format(subcategory.title)); // FIXME: Can't use GtkContainer.child_get_property. characterList.title = subcategory.title; this.add_titled(characterList, subcategory.name, subcategory.title); } characterList = this._createRecentCharacterList( category.name, // TRANSLATORS: %s will be either 'emojis' or 'letters' _('Recently Used %s Character List').format(category.title), category.category); this._recentCharacterLists[category.name] = characterList; if (i > 0) { let separator = new Gtk.Separator({}); recentBox.pack_start(separator, false, false, 0); } recentBox.pack_start(characterList, false, false, 0); } let scroll = new Gtk.ScrolledWindow({ hscrollbar_policy: Gtk.PolicyType.NEVER, hexpand: false, }); scroll.add(recentBox); recentBox.show_all(); scroll.show_all(); // FIXME: Can't use GtkContainer.child_get_property. scroll.title = _('Recently Used'); this.add_titled(scroll, 'recent', scroll.title); characterList = this._createCharacterList( 'search-result', _('Search Result Character List')); // FIXME: Can't use GtkContainer.child_get_property. characterList.title = _("Search Result"); this.add_named(characterList, 'search-result'); // FIXME: Can't use GSettings.bind with 'as' from Gjs let recentCharacters = Main.settings.get_value('recent-characters'); this.recentCharacters = recentCharacters.get_strv(); this._maxRecentCharacters = 100; Main.settings.bind('max-recent-characters', this, 'max-recent-characters', Gio.SettingsBindFlags.DEFAULT); } _createCharacterList(name, accessible_name) { const characterList = new CharacterList.CharacterListView({ fontFilter: this._fontFilter, }); characterList.get_accessible().accessible_name = accessible_name; characterList.connect('character-selected', (widget, uc) => this._handleCharacterSelected(widget, uc)); this._characterLists[name] = characterList; return characterList; } _createRecentCharacterList(name, accessible_name, category) { const characterList = new CharacterList.RecentCharacterListView({ fontFilter: this._fontFilter, category: category }); characterList.get_accessible().accessible_name = accessible_name; characterList.connect('character-selected', (widget, uc) => this._handleCharacterSelected(widget, uc)); this._characterLists[name] = characterList; return characterList; } searchByKeywords(keywords) { this.visible_child_name = 'search-result'; this.visible_child.searchByKeywords(keywords); } cancelSearch() { const characterList = this.get_child_by_name('search-result'); characterList.cancelSearch(); } setPage(category) { if (category.name === 'recent') { if (this.recentCharacters.length === 0) this.visible_child_name = 'empty-recent'; else { let categories = this._categoryListView.getCategoryList(); for (let i in categories) { let category = categories[i]; let characterList = this._recentCharacterLists[category.name]; characterList.setCharacters(this.recentCharacters); } this.visible_child_name = 'recent'; } } else { let characterList = this.get_child_by_name(category.name); characterList.searchByCategory(category); this.visible_child = characterList; } } addToRecent(uc) { if (this.recentCharacters.indexOf(uc) < 0) { this.recentCharacters.unshift(uc); if (this.recentCharacters.length > this._maxRecentCharacters) this.recentCharacters = this.recentCharacters.slice( 0, this._maxRecentCharacters); Main.settings.set_value( 'recent-characters', GLib.Variant.new_strv(this.recentCharacters)); } } _addToRecent(widget, uc) { this.addToRecent(uc); } _handleCharacterSelected(widget, uc) { const dialog = new Character.CharacterDialog({ character: uc, modal: true, transient_for: this.get_toplevel(), fontDescription: this._fontFilter.fontDescription }); dialog.show(); dialog.connect('character-copied', (widget, uc) => this._addToRecent(widget, uc)); dialog.connect('response', function(self, response_id) { if (response_id == Gtk.ResponseType.CLOSE) dialog.destroy(); }); } }); (uuay)
Close