[Xfce4-commits] [panel-plugins/xfce4-whiskermenu-plugin] 04/44: Add support for desktop actions. (bug #11787)

noreply at xfce.org noreply at xfce.org
Wed Feb 1 15:12:50 CET 2017


This is an automated email from the git hooks/post-receive script.

gottcode pushed a commit to annotated tag v1.7.0
in repository panel-plugins/xfce4-whiskermenu-plugin.

commit d3a365acb5de82cadef08c670a2525a48ade8110
Author: Graeme Gott <graeme at gottcode.org>
Date:   Sun Oct 23 19:41:51 2016 -0400

    Add support for desktop actions. (bug #11787)
---
 panel-plugin/launcher.cpp | 91 +++++++++++++++++++++++++++++++++++++++++++++++
 panel-plugin/launcher.h   | 60 ++++++++++++++++++++++++++++++-
 panel-plugin/page.cpp     | 40 +++++++++++++++++++++
 panel-plugin/page.h       |  2 ++
 panel-plugin/slot.h       | 41 ++++++++++++++++++++-
 5 files changed, 232 insertions(+), 2 deletions(-)

diff --git a/panel-plugin/launcher.cpp b/panel-plugin/launcher.cpp
index fcc2d50..7c3396e 100644
--- a/panel-plugin/launcher.cpp
+++ b/panel-plugin/launcher.cpp
@@ -185,12 +185,30 @@ Launcher::Launcher(GarconMenuItem* item) :
 	{
 		m_search_command = normalize(command);
 	}
+
+	// Fetch desktop actions
+#ifdef GARCON_TYPE_MENU_ITEM_ACTION
+	GList* actions = garcon_menu_item_get_actions(m_item);
+	for (GList* i = actions; i != NULL; i = i->next)
+	{
+		GarconMenuItemAction* action = garcon_menu_item_get_action(m_item, reinterpret_cast<gchar*>(i->data));
+		if (action)
+		{
+			m_actions.push_back(new DesktopAction(action));
+		}
+	}
+	g_list_free(actions);
+#endif
 }
 
 //-----------------------------------------------------------------------------
 
 Launcher::~Launcher()
 {
+	for (std::vector<DesktopAction*>::size_type i = 0, end = m_actions.size(); i < end; ++i)
+	{
+		delete m_actions[i];
+	}
 }
 
 //-----------------------------------------------------------------------------
@@ -274,6 +292,79 @@ void Launcher::run(GdkScreen* screen) const
 
 //-----------------------------------------------------------------------------
 
+void Launcher::run(GdkScreen* screen, DesktopAction* action) const
+{
+	const gchar* string = action->get_command();
+	if (exo_str_is_empty(string))
+	{
+		return;
+	}
+	std::string command(string);
+
+	// Expand the field codes
+	size_t length = command.length() - 1;
+	for (size_t i = 0; i < length; ++i)
+	{
+		if (G_UNLIKELY(command[i] == '%'))
+		{
+			switch (command[i + 1])
+			{
+			case 'i':
+				replace_with_quoted_string(command, i, "--icon ", action->get_icon());
+				break;
+
+			case 'c':
+				replace_with_quoted_string(command, i, action->get_name());
+				break;
+
+			case 'k':
+				replace_and_free_with_quoted_string(command, i, garcon_menu_item_get_uri(m_item));
+
+			case '%':
+				command.erase(i, 1);
+				break;
+
+			case 'f':
+				// unsupported, pass in a single file dropped on launcher
+			case 'F':
+				// unsupported, pass in a list of files dropped on launcher
+			case 'u':
+				// unsupported, pass in a single URL dropped on launcher
+			case 'U':
+				// unsupported, pass in a list of URLs dropped on launcher
+			default:
+				command.erase(i, 2);
+				break;
+			}
+			length = command.length() - 1;
+		}
+	}
+
+	// Parse and spawn command
+	gchar** argv;
+	gboolean result = false;
+	GError* error = NULL;
+	if (g_shell_parse_argv(command.c_str(), NULL, &argv, &error))
+	{
+		result = xfce_spawn_on_screen(screen,
+				garcon_menu_item_get_path(m_item),
+				argv, NULL, G_SPAWN_SEARCH_PATH,
+				garcon_menu_item_supports_startup_notification(m_item),
+				gtk_get_current_event_time(),
+				action->get_icon(),
+				&error);
+		g_strfreev(argv);
+	}
+
+	if (G_UNLIKELY(!result))
+	{
+		xfce_dialog_show_error(NULL, error, _("Failed to execute command \"%s\"."), string);
+		g_error_free(error);
+	}
+}
+
+//-----------------------------------------------------------------------------
+
 guint Launcher::search(const Query& query)
 {
 	// Prioritize matches in favorites and recent, then favories, and then recent
diff --git a/panel-plugin/launcher.h b/panel-plugin/launcher.h
index d13733d..f21d1c9 100644
--- a/panel-plugin/launcher.h
+++ b/panel-plugin/launcher.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013, 2015 Graeme Gott <graeme at gottcode.org>
+ * Copyright (C) 2013, 2015, 2016 Graeme Gott <graeme at gottcode.org>
  *
  * This library is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -21,12 +21,62 @@
 #include "element.h"
 
 #include <string>
+#include <vector>
 
 #include <garcon/garcon.h>
 
 namespace WhiskerMenu
 {
 
+struct DesktopAction
+{
+#ifdef GARCON_TYPE_MENU_ITEM_ACTION
+
+public:
+	DesktopAction(GarconMenuItemAction* action) :
+		m_action(action)
+	{
+	}
+
+	const gchar* get_name() const
+	{
+		return garcon_menu_item_action_get_name(m_action);
+	}
+
+	const gchar* get_icon() const
+	{
+		return garcon_menu_item_action_get_icon_name(m_action);
+	}
+
+	const gchar* get_command() const
+	{
+		return garcon_menu_item_action_get_command(m_action);
+	}
+
+private:
+	GarconMenuItemAction* m_action;
+
+#else
+
+public:
+	const gchar* get_name() const
+	{
+		return NULL;
+	}
+
+	const gchar* get_icon() const
+	{
+		return NULL;
+	}
+
+	const gchar* get_command() const
+	{
+		return NULL;
+	}
+
+#endif
+};
+
 class Launcher : public Element
 {
 public:
@@ -42,6 +92,11 @@ public:
 		return Type;
 	}
 
+	std::vector<DesktopAction*> get_actions() const
+	{
+		return m_actions;
+	}
+
 	const gchar* get_display_name() const
 	{
 		return m_display_name;
@@ -64,6 +119,8 @@ public:
 
 	void run(GdkScreen* screen) const;
 
+	void run(GdkScreen* screen, DesktopAction* action) const;
+
 	guint search(const Query& query);
 
 	enum SearchFlag
@@ -81,6 +138,7 @@ private:
 	std::string m_search_comment;
 	std::string m_search_command;
 	guint m_search_flags;
+	std::vector<DesktopAction*> m_actions;
 };
 
 }
diff --git a/panel-plugin/page.cpp b/panel-plugin/page.cpp
index 057fa4d..10fae6e 100644
--- a/panel-plugin/page.cpp
+++ b/panel-plugin/page.cpp
@@ -139,6 +139,29 @@ void Page::item_activated(GtkTreeView* view, GtkTreePath* path, GtkTreeViewColum
 
 //-----------------------------------------------------------------------------
 
+void Page::item_action_activated(GtkMenuItem* menuitem, DesktopAction* action)
+{
+	Launcher* launcher = get_selected_launcher();
+	if (!launcher)
+	{
+		return;
+	}
+
+	// Add to recent
+	if (remember_launcher(launcher))
+	{
+		m_window->get_recent()->add(launcher);
+	}
+
+	// Hide window
+	m_window->hide();
+
+	// Execute app
+	launcher->run(gtk_widget_get_screen(GTK_WIDGET(menuitem)), action);
+}
+
+//-----------------------------------------------------------------------------
+
 gboolean Page::view_button_press_event(GtkWidget* view, GdkEvent* event)
 {
 	GdkEventButton* event_button = reinterpret_cast<GdkEventButton*>(event);
@@ -194,6 +217,23 @@ void Page::create_context_menu(GtkTreeIter* iter, GdkEvent* event)
 	menuitem = gtk_separator_menu_item_new();
 	gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
 
+	const std::vector<DesktopAction*> actions = launcher->get_actions();
+	if (!actions.empty())
+	{
+		for (std::vector<DesktopAction*>::size_type i = 0, end = actions.size(); i < end; ++i)
+		{
+			DesktopAction* action = actions[i];
+			menuitem = gtk_image_menu_item_new_with_label(action->get_name());
+			GtkWidget* image = gtk_image_new_from_icon_name(action->get_icon(), GTK_ICON_SIZE_MENU);
+			gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuitem), image);
+			g_signal_connect_slot(menuitem, "activate", &Page::item_action_activated, this, action);
+			gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
+		}
+
+		menuitem = gtk_separator_menu_item_new();
+		gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
+	}
+
 	if (!m_window->get_favorites()->contains(launcher))
 	{
 		menuitem = gtk_image_menu_item_new_with_label(_("Add to Favorites"));
diff --git a/panel-plugin/page.h b/panel-plugin/page.h
index c11f75e..25a0851 100644
--- a/panel-plugin/page.h
+++ b/panel-plugin/page.h
@@ -23,6 +23,7 @@
 namespace WhiskerMenu
 {
 
+class DesktopAction;
 class Launcher;
 class LauncherView;
 class Window;
@@ -54,6 +55,7 @@ protected:
 private:
 	virtual bool remember_launcher(Launcher* launcher);
 	void item_activated(GtkTreeView* view, GtkTreePath* path, GtkTreeViewColumn*);
+	void item_action_activated(GtkMenuItem* menuitem, DesktopAction* action);
 	gboolean view_button_press_event(GtkWidget* view, GdkEvent* event);
 	gboolean view_popup_menu_event(GtkWidget* view);
 	void on_unmap();
diff --git a/panel-plugin/slot.h b/panel-plugin/slot.h
index f0202b2..a30a177 100644
--- a/panel-plugin/slot.h
+++ b/panel-plugin/slot.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Graeme Gott <graeme at gottcode.org>
+ * Copyright (C) 2013, 2016 Graeme Gott <graeme at gottcode.org>
  *
  * This library is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -96,6 +96,45 @@ gulong g_signal_connect_slot(gpointer instance, const gchar* detailed_signal, R(
 			after ? G_CONNECT_AFTER : GConnectFlags(0));
 }
 
+// Member function with 1 parameter and 1 bound parameter
+template<typename T, typename R, typename A1, typename A2>
+gulong g_signal_connect_slot(gpointer instance, const gchar* detailed_signal, R(T::*member)(A1,A2), T* obj, A2 bound1, bool after = false)
+{
+	class Slot
+	{
+		T* m_instance;
+		R (T::*m_member)(A1,A2);
+		A2 m_bound1;
+
+	public:
+		Slot(T* instance, R (T::*member)(A1,A2), A2 bound1) :
+			m_instance(instance),
+			m_member(member),
+			m_bound1(bound1)
+		{
+		}
+
+		static R invoke(A1 a1, gpointer user_data)
+		{
+			Slot* slot = reinterpret_cast<Slot*>(user_data);
+			return (slot->m_instance->*slot->m_member)(a1, slot->m_bound1);
+		}
+
+		static void destroy(gpointer data, GClosure*)
+		{
+			delete reinterpret_cast<Slot*>(data);
+		}
+	};
+	R (*invoke_slot)(A1,gpointer) = &Slot::invoke;
+	void (*destroy_slot)(gpointer, GClosure*) = &Slot::destroy;
+
+	return g_signal_connect_data(instance, detailed_signal,
+			reinterpret_cast<GCallback>(invoke_slot),
+			new Slot(obj, member, bound1),
+			destroy_slot,
+			after ? G_CONNECT_AFTER : GConnectFlags(0));
+}
+
 // Member function with 2 parameters
 template<typename T, typename R, typename A1, typename A2>
 gulong g_signal_connect_slot(gpointer instance, const gchar* detailed_signal, R(T::*member)(A1,A2), T* obj, bool after = false)

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the Xfce4-commits mailing list