- // Copyright (c) 2010 Trent McPheron <twilightinzero@gmail.com>
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to deal
- // in the Software without restriction, including without limitation the rights
- // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- // copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- // THE SOFTWARE.
- using Xfce;
- using Gtk;
- using Pango;
- using Wnck;
- ///////////////////
- // Namebar
- ///////////////////
- public class NamebarPlugin : GLib.Object
- {
- ///////////////////
- // Init stuff
- ///////////////////
- static NamebarPlugin namebar;
- public static void register (Xfce.PanelPlugin plugin)
- {
- namebar = new NamebarPlugin (plugin);
- plugin.size_changed.connect((p, s) => {
- plugin.set_size_request(namebar.size, -1);
- });
- }
- public static int main (string[] args)
- {
- return Xfce.PanelPluginRegisterExternal(ref args, register);
- }
- ///////////////////
- // Properties
- ///////////////////
- public bool only_max { get; set; default = true; }
- public int16 size { get; set; default = 240; }
- public bool expand { get; set; default = true; }
- public bool active_bold { get; set; default = true; }
- public bool passive_bold { get; set; default = true; }
- public Color active_color { get; set; default = Color(); }
- public Color passive_color { get; set; default = Color(); }
- ///////////////////
- // Fields
- ///////////////////
- // Xfce4 Panel Plugin.
- private weak PanelPlugin plugin;
- // Wnck stuff.
- private unowned Screen screen;
- private unowned Wnck.Window window;
- // Gtk widgets.
- private HBox box;
- private Image window_icon;
- private Image minimize_icon;
- private Image max_res_icon;
- private Image close_icon;
- private Label title_label;
- // Theme stuff.
- private List<File> theme_list;
- private Theme theme;
- ///////////////////
- // Constructor
- ///////////////////
- // The real constructor.
- public NamebarPlugin (PanelPlugin plugin)
- {
- // Panel plugin.
- this.plugin = plugin;
- // Default colors.
- active_color.parse("#ECECEC");
- passive_color.parse("#888888");
- // Default theme.
- File tf = File.new_for_path("~/.config/namebar/themes/New Wave-ish");
- theme = Theme(tf);
- // Get wnck ready.
- set_client_type(ClientType.PAGER);
- screen = Screen.get_default();
- // Wnck.Window icon.
- EventBox eb1 = new EventBox();
- eb1.visible_window = false;
- window_icon = new Image();
- eb1.add(window_icon);
- // Title label.
- EventBox eb2 = new EventBox();
- eb2.visible_window = false;
- title_label = new Label();
- title_label.set_alignment(0.0, 0.5);
- title_label.ellipsize = EllipsizeMode.END;
- eb2.add(title_label);
- // Minimize button.
- EventBox eb3 = new EventBox();
- eb3.visible_window = false;
- minimize_icon = new Image();
- eb3.add(minimize_icon);
- // Maximize/Restore button.
- EventBox eb4 = new EventBox();
- eb4.visible_window = false;
- max_res_icon = new Image();
- eb4.add(max_res_icon);
- // Close button.
- EventBox eb5 = new EventBox();
- eb5.visible_window = false;
- close_icon = new Image();
- eb5.add(close_icon);
- // Create container box.
- box = new HBox();
- box.spacing = 0;
- box.pack_start(eb1, false, false, 0);
- box.pack_start(eb2, true, true, 2);
- box.pack_start(eb3, false, false, 0);
- box.pack_start(eb4, false, false, 0);
- box.pack_start(eb5, false, false, 0);
- plugin.add(box);
- plugin.set_expand(true);
- // Connect signals.
- screen.active_window_changed.connect(find_window);
- screen.window_closed.connect(find_window);
- eb2.button_press_event.connect((w, e) => { window.activate(e.time); });
- eb3.enter_notify_event.connect(button_entered);
- eb3.leave_notify_event.connect(button_left);
- eb3.button_press_event.connect(button_pressed);
- eb3.button_release_event.connect(button_released);
- eb4.enter_notify_event.connect(button_entered);
- eb4.leave_notify_event.connect(button_left);
- eb4.button_press_event.connect(button_pressed);
- eb4.button_release_event.connect(button_released);
- eb5.enter_notify_event.connect(button_entered);
- eb5.leave_notify_event.connect(button_left);
- eb5.button_press_event.connect(button_pressed);
- eb5.button_release_event.connect(button_released);
- // Find a window to show.
- find_window();
- }
- ///////////////////
- // Functions
- ///////////////////
- // Find a list of themes.
- private List<Theme> find_themes ()
- {
- List<Theme> list = new List<Theme>();
- File usr_dir = File.new_for_path("/usr/share/namebar/themes");
- File home_dir = File.new_for_path("~/.config/namebar/themes");
- File[] dirs = { usr_dir, home_dir };
- // Check each directory to see if it exists.
- for (uint8 i = 0; i < 2; i++)
- if (dirs[i].query_exists())
- {
- // Get an enumerator for the directory.
- FileEnumerator enumerator =
- usr_dir.enumerate_children(
- FILE_ATTRIBUTE_STANDARD_NAME, 0, null);
- // Iterate through all the children and try to
- // load the themes in each. If successful, add
- // them to the theme list.
- FileInfo next_file;
- while ((next_file = enumerator.next_file(null)) != null)
- {
- File theme_file = File.get_child(next_file.get_name());
- Theme theme = Theme(theme_file);
- if (theme.valid)
- list.append(theme);
- }
- }
- // If the theme list is empty, let the user know.
- if (list.length() == 0)
- stdout.printf("There are no valid themes.");
- // Return the list.
- return list;
- }
- // Refreshes the theme details and label attributes.
- private void refresh_theme ()
- {
- set_button_state(minimize_icon, ButtonState.NORMAL);
- set_button_state(max_res_icon, ButtonState.NORMAL);
- set_button_state(close_icon, ButtonState.NORMAL);
- bool active = window.is_active();
- bool bold = (active ? active_bold : passive_bold);
- AttrList al = new AttrList();
- AttrColor ac = new AttrColor();
- ac.color = (active ? active_color : passive_color);
- Attribute aw = attr_weight_new(Weight.BOLD);
- title_label.attributes.change(ac);
- title_label.attributes.change(aw);
- }
- // Changes the currently shown window.
- private void set_current_window (Wnck.Window new_win)
- {
- // We don't need the old window firing events.
- if (window != null)
- {
- window.name_changed.disconnect(window_name_changed);
- window.icon_changed.disconnect(window_icon_changed);
- window.state_changed.disconnect(find_window);
- }
- // Set the window.
- window = new_win;
- // Connect the new events.
- window.name_changed.connect(window_name_changed);
- window.icon_changed.connect(window_icon_changed);
- window.state_changed.connect(find_window);
- // Reset attributes.
- window_name_changed();
- window_icon_changed();
- refresh_theme();
- // Show everything in the box.
- box.show_all();
- }
- // Hides the namebar if there is no valid window.
- private void set_none ()
- {
- // Disconnect the old window's events.
- if (window != null)
- {
- window.name_changed.disconnect(window_name_changed);
- window.icon_changed.disconnect(window_icon_changed);
- window.state_changed.disconnect(find_window);
- }
- // Set window to null.
- window = null;
- // Hide everything in the box.
- box.hide_all();
- }
- // Finds a window to show.
- private void find_window ()
- {
- // Get the active window.
- unowned Wnck.Window active_window = screen.get_active_window();
- // If we're not only using max'd windows, check the
- // active window and set the window if it fits.
- if (!only_max && !active_window.is_skip_tasklist() &&
- (active_window.get_window_type() == Wnck.WindowType.NORMAL ||
- active_window.get_window_type() == Wnck.WindowType.DIALOG))
- {
- set_window(active_window);
- return;
- }
- // If we're using the topmost maximized window...
- if (only_max)
- {
- // Get the list of stacked windows.
- List<Wnck.Window> window_stack = screen.get_windows_stacked();
- // Iterate through in reverse.
- for (uint16 i = window_stack.length() - 1; i >= 0; i--)
- {
- // Check the window, and if it fits, set it.
- Wnck.Window w = window_stack.nth_data(i);
- if (w.is_maximized() &&
- !w.is_minimized() &&
- !w.is_skip_tasklist() &&
- (w.get_window_type() == Wnck.WindowType.NORMAL ||
- w.get_window_type() == Wnck.WindowType.DIALOG))
- {
- set_window(w);
- return;
- }
- }
- }
- // If we still don't have a window,
- // set it to none.
- set_none();
- }
- // Sets the state of a button.
- private void set_button_state (Image img, ButtonState bs)
- {
- // Get stuff ready.
- bool active = window.is_active();
- ThemeButton tb;
- // Determine which button we're on.
- if (img == minimize_icon) tb = ThemeButton.MINIMIZE;
- else if (img == close_icon) tb = ThemeButton.CLOSE;
- else
- {
- if (window.is_maximized()) tb = ThemeButton.MAXIMIZE;
- else tb = ThemeButton.RESTORE;
- }
- // Set the pixbuf on the image.
- img.pixbuf = theme.get_pixbuf(active, tb, bs);
- }
- ///////////////////
- // Events
- ///////////////////
- // Emitted when the window's name changes.
- private void window_name_changed ()
- {
- string name = window.get_name();
- title_label.label = name;
- title_label.tooltip_text = name;
- }
- // Emitted when the window's icon changes.
- // I don't know anything about disconnecting lambda
- // expressions, so this one-line method's here.
- private void window_icon_changed ()
- {
- window_icon.pixbuf = window.get_mini_icon();
- }
- // Changes the icon once a button is entered.
- private void button_entered (Widget sender)
- {
- Image img = (sender as EventBox).child as Image;
- set_button_state(img, ButtonState.HOVER);
- }
- // Changes the icon once a button is left.
- private void button_left (Widget sender)
- {
- Image img = (sender as EventBox).child as Image;
- set_button_state(img, ButtonState.NORMAL);
- }
- // Changes the icon once a button is pressed.
- private void button_pressed (Widget sender, Gdk.EventButton event)
- {
- if (event.button == 1)
- {
- Image img = (sender as EventBox).child as Image;
- set_button_state(img, ButtonState.HOVER);
- }
- }
- // Performs an action when an button is released.
- private void button_released (Widget sender, Gdk.EventButton event)
- {
- // Preparation for below check.
- int x, y;
- sender.get_pointer(out x, out y);
- Allocation a = sender.allocation;
- // Abort method if the main button wasn't released
- // inside the event box.
- if (x < 0 || y < 0 ||
- x > a.width || y > a.height ||
- event.button != 1) return;
- // Determine what to do based on which icon was
- // clicked and do it.
- Image img = (sender as EventBox).child as Image;
- if (img = minimize_icon) window.minimize();
- else if (img = close_icon) window.close(event.time);
- else if (img = max_res_icon)
- {
- if (window.is_maximized()) window.unmaximize();
- else window.maximize();
- }
- // Set the button state to normal.
- set_button_state(img, ButtonState.NORMAL);
- }
- }
- ///////////////////
- // XFCE Module
- ///////////////////
- [ModuleInit]
- public Type xfce_panel_module_init (TypeModule module) {
- return typeof(NamebarPlugin);
- }
