midori/midori/midori-window.vala

250 lines
9.9 KiB
Vala

/*
Copyright (C) 2015 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
namespace Midori {
public class Window : Gtk.Window {
Gtk.Widget? _toolbar = null;
public Gtk.Widget? toolbar { get {
if (_toolbar == null) {
#if HAVE_GTK3
if (strcmp (Environment.get_variable ("GTK_CSD"), "1") == 0) {
var toolbar = new Gtk.HeaderBar ();
toolbar.show_close_button = true;
toolbar.show ();
toolbar.get_style_context ().add_class ("midori-titlebar");
_toolbar = toolbar;
return _toolbar;
}
#endif
var toolbar = new Gtk.Toolbar ();
toolbar.show_arrow = true;
#if HAVE_GTK3
toolbar.get_style_context ().add_class ("primary-toolbar");
hide_titlebar_when_maximized = true;
#endif
toolbar.popup_context_menu.connect ((x, y, button) => {
return button == 3 && context_menu (toolbar); });
_toolbar = toolbar;
}
return _toolbar;
} }
public string actions { get; set; default = ""; }
string extra_actions { get; set; default = ""; }
List<Gtk.ActionGroup> action_groups;
public signal bool context_menu (Gtk.Widget widget, Gtk.Action? action=null);
Gtk.Box? box = null;
List<Gtk.Widget> toolbars;
Gtk.Widget? _contents = null;
public Gtk.Widget? contents { get {
return _contents;
} set {
if (_contents != null)
box.remove (_contents);
_contents = value;
_contents.show ();
if (box != null)
box.pack_end (_contents, true, true, 0);
} }
public void add_action_group (Gtk.ActionGroup action_group) {
action_groups.append (action_group);
}
public bool show_menubar { get; set; default = false; }
[CCode (type = "GtkWidget*")]
public Window () {
}
public Gtk.ToolItem? get_tool_item (string name) {
/* Name is the empty string if actions has ,, or trailing , */
if (name == "")
return null;
/* Shown in the notebook, no need to include in the toolbar */
if (name == "TabNew")
return null;
foreach (unowned Gtk.ActionGroup action_group in action_groups) {
var action = action_group.get_action (name);
if (action != null) {
return create_tool_item (action);
}
}
warning ("Action %s not known to Window", name);
return null;
}
Gtk.ToolItem create_tool_item (Gtk.Action action) {
var toolitem = (Gtk.ToolItem)action.create_tool_item ();
/* Show label if button has no icon of any kind */
if (action.icon_name == null && action.stock_id == null && action.gicon == null)
toolitem.is_important = true;
toolitem.get_child ().button_press_event.connect ((event) => {
return event.button == 3 && context_menu (toolitem, action); });
if (action.name == "CompactMenu")
{
toolitem.visible = !show_menubar;
bind_property ("show-menubar", toolitem, "visible",
BindingFlags.DEFAULT | BindingFlags.INVERT_BOOLEAN);
}
return toolitem;
}
/**
* Adds an action to the (browser) window.
* Typically it will be displayed in the primary toolbar or headerbar.
*
* If @action is a ContextAction a menu will be displayed.
*
* Since: 0.6.0
**/
public void add_action (Gtk.Action action) {
action_groups.nth_data (0).add_action (action);
extra_actions += "," + action.name;
update_toolbar ();
}
/**
* Remove an action from the (browser) window.
*
* Since: 0.6.0
**/
public void remove_action (Gtk.Action action) {
action_groups.nth_data (0).remove_action (action);
extra_actions = extra_actions.replace ("," + action.name, "");
update_toolbar ();
}
void update_toolbar () {
var container = (Gtk.Container)_toolbar;
foreach (unowned Gtk.Widget toolitem in container.get_children ())
container.remove (toolitem);
/* Always include app menu (visible depending on menubar) and extensions. */
string all_actions;
if ("CompactMenu" in actions)
all_actions = actions.replace ("CompactMenu", extra_actions + ",CompactMenu");
else
all_actions = actions + "," + extra_actions + ",CompactMenu";
string[] names = all_actions.split (",");
#if HAVE_GTK3
var headerbar = _toolbar as Gtk.HeaderBar;
if (headerbar != null) {
var tail = new List<Gtk.ToolItem> ();
foreach (unowned string name in names) {
var toolitem = get_tool_item (name);
if (toolitem == null)
continue;
var widget = toolitem.get_child ();
if (widget is Gtk.Alignment)
widget = ((Gtk.Bin)widget).get_child ();
if (name == "Location") {
widget.set ("margin-top", 1, "margin-bottom", 1);
((Gtk.Entry)widget).width_chars = 36;
headerbar.custom_title = toolitem;
headerbar.custom_title.set (
"margin-start", 25, "margin-end", 25,
"margin-top", 5, "margin-bottom", 5);
} else if (name == "Search") {
((Gtk.Entry)widget).width_chars = 12;
tail.append (toolitem);
} else if (all_actions.index_of (name) > all_actions.index_of ("Location"))
tail.append (toolitem);
else
headerbar.pack_start (toolitem);
}
/* Pack end appends, so we need to pack in reverse order */
tail.reverse ();
foreach (unowned Gtk.ToolItem toolitem in tail)
headerbar.pack_end (toolitem);
set_titlebar (headerbar);
return;
}
#endif
var toolbar = (Gtk.Toolbar)_toolbar;
string? previous = null;
Gtk.ToolItem? toolitem_previous = null;
foreach (unowned string name in names) {
var toolitem = get_tool_item (name);
if (toolitem == null)
continue;
if ((name == "Location" || name == "Search")
&& (previous == "Location" || previous == "Search")) {
toolitem_previous.ref ();
toolbar.remove (toolitem_previous);
var paned = new Midori.PanedAction ();
paned.set_child1 (toolitem_previous, previous, previous != "Search", true);
paned.set_child2 (toolitem, name, name != "Search", true);
/* Midori.Settings.search-width on Midori.Browser.settings */
Midori.Settings? settings = null;
get ("settings", ref settings);
var sizeable = name == "Search" ? toolitem : toolitem_previous;
sizeable.size_allocate.connect ((allocation) => {
settings.set ("search-width", allocation.width);
});
var requester = previous == "Search" ? toolitem_previous : toolitem;
requester.set_size_request (settings.search_width, -1);
toolitem = (Gtk.ToolItem)paned.create_tool_item ();
previous = null;
toolitem_previous.unref ();
toolitem_previous = null;
} else {
previous = name;
toolitem_previous = toolitem;
}
toolbar.insert (toolitem, -1);
}
}
public void add_toolbar (Gtk.Widget toolbar) {
var _toolbar = toolbar as Gtk.Toolbar;
if (_toolbar != null) {
#if HAVE_GTK3
get_style_context ().add_class ("secondary-toolbar");
#endif
_toolbar.popup_context_menu.connect ((x, y, button) => {
return button == 3 && context_menu (toolbar);
});
}
if (box == null)
toolbars.append (toolbar);
else
box.pack_start (toolbar, false, false);
}
construct {
box = new Gtk.VBox (false, 0);
box.show ();
add (box);
foreach (unowned Gtk.Widget toolbar in toolbars) {
if (toolbar is Gtk.MenuBar)
box.pack_start (toolbar, false, false);
}
if (toolbar is Gtk.Toolbar)
box.pack_start (toolbar, false, false);
foreach (unowned Gtk.Widget toolbar in toolbars) {
if (!(toolbar is Gtk.MenuBar))
box.pack_start (toolbar, false, false);
}
if (_contents != null)
box.pack_end (_contents, true, true, 0);
if (actions != "")
update_toolbar ();
notify["actions"].connect ((pspec) => { update_toolbar (); });
}
}
}