Browse Source

Initial version of the window menu plugin (the old window list).

Most of the code is working, new way of urgentcy notification is
not full working yet. Properties dialog is not working at all.
upstream/xfce4-panel-4.10.1
Nick Schermer 12 years ago
parent
commit
70f1a37b17
  1. 1
      configure.in.in
  2. 3
      plugins/Makefile.am
  3. 81
      plugins/windowmenu/Makefile.am
  4. 248
      plugins/windowmenu/windowmenu-dialog.glade
  5. 830
      plugins/windowmenu/windowmenu.c
  6. 9
      plugins/windowmenu/windowmenu.desktop.in.in
  7. 41
      plugins/windowmenu/windowmenu.h

1
configure.in.in

@ -238,5 +238,6 @@ plugins/separator/Makefile
plugins/showdesktop/Makefile
plugins/systray/Makefile
plugins/tasklist/Makefile
plugins/windowmenu/Makefile
po/Makefile.in
])

3
plugins/Makefile.am

@ -7,6 +7,7 @@ SUBDIRS = \
separator \
showdesktop \
systray \
tasklist
tasklist \
windowmenu
# vi:set ts=8 sw=8 noet ai nocindent syntax=automake:

81
plugins/windowmenu/Makefile.am

@ -0,0 +1,81 @@
# $Id$
INCLUDES = \
-I$(top_srcdir) \
-DG_LOG_DOMAIN=\"libwindowmenu\" \
-DLOCALEDIR=\"$(localedir)\" \
-DWNCK_I_KNOW_THIS_IS_UNSTABLE \
$(PLATFORM_CPPFLAGS)
plugindir = \
$(libdir)/xfce4/panel-plugins
plugin_LTLIBRARIES = \
libwindowmenu.la
libwindowmenu_built_sources = \
windowmenu-dialog_glade.h
libwindowmenu_la_SOURCES = \
$(libwindowmenu_built_sources) \
windowmenu.c \
windowmenu.h
libwindowmenu_la_CFLAGS = \
$(GTK_CFLAGS) \
$(EXO_CFLAGS) \
$(XFCONF_CFLAGS) \
$(LIBXFCE4UTIL_CFLAGS) \
$(LIBXFCE4UI_CFLAGS) \
$(LIBWNCK_CFLAGS) \
$(PLATFORM_CFLAGS)
libwindowmenu_la_LDFLAGS = \
-avoid-version \
-module \
-no-undefined \
$(PLATFORM_LDFLAGS)
libwindowmenu_la_LIBADD = \
$(top_builddir)/libxfce4panel/libxfce4panel.la \
$(EXO_LIBS) \
$(GTK_LIBS) \
$(XFCONF_LIBS) \
$(LIBXFCE4UTIL_LIBS) \
$(LIBXFCE4UI_LIBS) \
$(LIBWNCK_LIBS)
libwindowmenu_la_DEPENDENCIES = \
$(top_builddir)/libxfce4panel/libxfce4panel.la
if MAINTAINER_MODE
BUILT_SOURCES = \
$(libwindowmenu_built_sources)
DISTCLEANFILES = \
$(libwindowmenu_built_sources)
windowmenu-dialog_glade.h: windowmenu-dialog.glade
exo-csource --static --strip-comments --strip-content --name=windowmenu_dialog_glade $< >$@
endif
#
# .desktop file
#
desktopdir = $(datadir)/xfce4/panel-plugins
desktop_in_in_files = windowmenu.desktop.in.in
desktop_in_files = $(desktop_in_in_files:.desktop.in.in=.desktop.in)
windowmenu.desktop.in: $(desktop_in_in_files)
sed -e "s,\@libdir\@,$(libdir),g" < $< > $@
desktop_DATA = $(desktop_in_files:.desktop.in=.desktop)
@INTLTOOL_DESKTOP_RULE@
EXTRA_DIST = \
windowmenu-dialog.glade \
$(desktop_in_in_files)
DISTCLEANFILES = \
$(desktop_DATA) \
$(desktop_in_files)
# vi:set ts=8 sw=8 noet ai nocindent syntax=automake:

248
plugins/windowmenu/windowmenu-dialog.glade

@ -0,0 +1,248 @@
<?xml version="1.0"?>
<interface>
<!-- interface-requires gtk+ 2.12 -->
<!-- interface-requires libxfce4ui 0.0 -->
<!-- interface-naming-policy toplevel-contextual -->
<object class="XfceTitledDialog" id="dialog">
<property name="title" translatable="yes">Window Menu Properties</property>
<property name="icon_name">gtk-properties</property>
<property name="type_hint">normal</property>
<property name="has_separator">False</property>
<child internal-child="vbox">
<object class="GtkVBox" id="dialog-vbox2">
<property name="visible">True</property>
<property name="spacing">2</property>
<child>
<object class="GtkVBox" id="vbox1">
<property name="visible">True</property>
<property name="border_width">6</property>
<property name="spacing">6</property>
<child>
<object class="GtkFrame" id="frame3">
<property name="visible">True</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkAlignment" id="alignment3">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<object class="GtkVBox" id="vbox3">
<property name="visible">True</property>
<property name="border_width">6</property>
<property name="spacing">6</property>
<child>
<object class="GtkHBox" id="hbox1">
<property name="visible">True</property>
<property name="spacing">12</property>
<child>
<object class="GtkLabel" id="label5">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Button layout:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkComboBox" id="button-layout">
<property name="visible">True</property>
<property name="model">layout-model</property>
<child>
<object class="GtkCellRendererText" id="cellrenderertext1"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="show-workspace-actions">
<property name="label" translatable="yes">Show workspace a_ctions</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_underline">True</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="checkbutton1">
<property name="label" translatable="yes">Enable _urgency notification</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_underline">True</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="label" translatable="yes">&lt;b&gt;Appearance&lt;/b&gt;</property>
<property name="use_markup">True</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkFrame" id="frame4">
<property name="visible">True</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkAlignment" id="alignment4">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<object class="GtkVBox" id="vbox5">
<property name="visible">True</property>
<property name="border_width">6</property>
<child>
<object class="GtkCheckButton" id="switch-workspace-on-unminimize">
<property name="label" translatable="yes">Restore minimized windows to current _workspace</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_underline">True</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="position">0</property>
</packing>
</child>
</object>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="label4">
<property name="visible">True</property>
<property name="label" translatable="yes">&lt;b&gt;Behaviour&lt;/b&gt;</property>
<property name="use_markup">True</property>
</object>
</child>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkFrame" id="frame2">
<property name="visible">True</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkAlignment" id="alignment2">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<object class="GtkVBox" id="vbox4">
<property name="visible">True</property>
<property name="border_width">6</property>
<property name="spacing">6</property>
<child>
<object class="GtkCheckButton" id="include-all-workspaces">
<property name="label" translatable="yes">Show windows from _all workspaces</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_underline">True</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="position">0</property>
</packing>
</child>
</object>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="label" translatable="yes">&lt;b&gt;Filtering&lt;/b&gt;</property>
<property name="use_markup">True</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
<child internal-child="action_area">
<object class="GtkHButtonBox" id="dialog-action_area2">
<property name="visible">True</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="close-button">
<property name="label" translatable="yes">gtk-close</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
</object>
</child>
<action-widgets>
<action-widget response="0">close-button</action-widget>
</action-widgets>
</object>
<object class="GtkListStore" id="layout-model">
<columns>
<!-- column-name title -->
<column type="gchararray"/>
</columns>
<data>
<row>
<col id="0" translatable="yes">Icon</col>
</row>
<row>
<col id="0" translatable="yes">Arrow</col>
</row>
</data>
</object>
</interface>

830
plugins/windowmenu/windowmenu.c

@ -0,0 +1,830 @@
/* $Id$ */
/*
* Copyright (C) 2008-2009 Nick Schermer <nick@xfce.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 the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This library 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 Library General Public License
* along with this library; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <xfconf/xfconf.h>
#include <exo/exo.h>
#include <libxfce4ui/libxfce4ui.h>
#include <libxfce4panel/libxfce4panel.h>
#include <libwnck/libwnck.h>
#include <gdk/gdkkeysyms.h>
#include <common/panel-private.h>
#include "windowmenu.h"
#include "windowmenu-dialog_glade.h"
#define ARROW_BUTTON_SIZE (12)
#define URGENT_FLAGS (WNCK_WINDOW_STATE_DEMANDS_ATTENTION | \
WNCK_WINDOW_STATE_URGENT)
struct _XfceWindowMenuPluginClass
{
XfcePanelPluginClass __parent__;
};
struct _XfceWindowMenuPlugin
{
XfcePanelPlugin __parent__;
/* the xfconf channel */
XfconfChannel *channel;
/* the screen we're showing */
WnckScreen *screen;
/* panel widgets */
GtkWidget *button;
GtkWidget *icon;
/* settings */
guint show_all_workspaces : 1;
guint enable_urgency_notify : 1;
/* urgent window counter */
gint urgent_windows;
};
static void window_menu_plugin_screen_changed (GtkWidget *widget, GdkScreen *previous_screen);
static void window_menu_plugin_construct (XfcePanelPlugin *panel_plugin);
static void window_menu_plugin_free_data (XfcePanelPlugin *panel_plugin);
static void window_menu_plugin_screen_position_changed (XfcePanelPlugin *panel_plugin, gint position);
static gboolean window_menu_plugin_size_changed (XfcePanelPlugin *panel_plugin, gint size);
static void window_menu_plugin_configure_plugin (XfcePanelPlugin *panel_plugin);
static void window_menu_plugin_active_window_changed (WnckScreen *screen, WnckWindow *previous_window, XfceWindowMenuPlugin *plugin);
static void window_menu_plugin_window_state_changed (WnckWindow *window, WnckWindowState changed_mask, WnckWindowState new_state, XfceWindowMenuPlugin *plugin);
static void window_menu_plugin_window_opened (WnckScreen *screen, WnckWindow *window, XfceWindowMenuPlugin *plugin);
static void window_menu_plugin_window_closed (WnckScreen *screen, WnckWindow *window, XfceWindowMenuPlugin *plugin);
static gboolean window_menu_plugin_button_press_event (GtkWidget *button, GdkEventButton *event, XfceWindowMenuPlugin *plugin);
static GtkWidget *window_menu_plugin_menu_new (XfceWindowMenuPlugin *plugin);
G_DEFINE_TYPE (XfceWindowMenuPlugin, window_menu_plugin, XFCE_TYPE_PANEL_PLUGIN);
/* register the panel plugin */
XFCE_PANEL_PLUGIN_REGISTER_OBJECT (XFCE_TYPE_WINDOW_MENU_PLUGIN);
static GQuark window_quark = 0;
static void
window_menu_plugin_class_init (XfceWindowMenuPluginClass *klass)
{
XfcePanelPluginClass *plugin_class;
GtkWidgetClass *gtkwidget_class;
gtkwidget_class = GTK_WIDGET_CLASS (klass);
gtkwidget_class->screen_changed = window_menu_plugin_screen_changed;
plugin_class = XFCE_PANEL_PLUGIN_CLASS (klass);
plugin_class->construct = window_menu_plugin_construct;
plugin_class->free_data = window_menu_plugin_free_data;
plugin_class->screen_position_changed = window_menu_plugin_screen_position_changed;
plugin_class->size_changed = window_menu_plugin_size_changed;
plugin_class->configure_plugin = window_menu_plugin_configure_plugin;
window_quark = g_quark_from_static_string ("window-list-window-quark");
}
static void
window_menu_plugin_init (XfceWindowMenuPlugin *plugin)
{
plugin->urgent_windows = 0;
plugin->show_all_workspaces = FALSE;
plugin->enable_urgency_notify = TRUE;
/* initialize xfconf */
xfconf_init (NULL);
/* show configure */
xfce_panel_plugin_menu_show_configure (XFCE_PANEL_PLUGIN (plugin));
/* create the widgets */
plugin->button = xfce_arrow_button_new (GTK_ARROW_NONE);
xfce_panel_plugin_add_action_widget (XFCE_PANEL_PLUGIN (plugin), plugin->button);
gtk_container_add (GTK_CONTAINER (plugin), plugin->button);
gtk_button_set_relief (GTK_BUTTON (plugin->button), GTK_RELIEF_NONE);
g_signal_connect (G_OBJECT (plugin->button), "button-press-event",
G_CALLBACK (window_menu_plugin_button_press_event), plugin);
plugin->icon = xfce_scaled_image_new_from_icon_name ("user-desktop");
gtk_container_add (GTK_CONTAINER (plugin->button), plugin->icon);
}
static void
window_menu_plugin_screen_changed (GtkWidget *widget,
GdkScreen *previous_screen)
{
XfceWindowMenuPlugin *plugin = XFCE_WINDOW_MENU_PLUGIN (widget);
GdkScreen *screen;
if (G_UNLIKELY (plugin->screen != NULL))
{
/* disconnect from the previous screen */
g_signal_handlers_disconnect_by_func (G_OBJECT (plugin->screen),
window_menu_plugin_active_window_changed, plugin);
g_signal_handlers_disconnect_by_func (G_OBJECT (plugin->screen),
window_menu_plugin_window_opened, plugin);
g_signal_handlers_disconnect_by_func (G_OBJECT (plugin->screen),
window_menu_plugin_window_closed, plugin);
}
/* get the wnck screen */
screen = gtk_widget_get_screen (widget);
panel_return_if_fail (GDK_IS_SCREEN (screen));
plugin->screen = wnck_screen_get (gdk_screen_get_number (screen));
/* connect signal to monitor this screen */
g_signal_connect (G_OBJECT (plugin->screen), "active-window-changed",
G_CALLBACK (window_menu_plugin_active_window_changed), plugin);
g_signal_connect (G_OBJECT (plugin->screen), "window-opened",
G_CALLBACK (window_menu_plugin_window_opened), plugin);
g_signal_connect (G_OBJECT (plugin->screen), "window-closed",
G_CALLBACK (window_menu_plugin_window_closed), plugin);
}
static void
window_menu_plugin_construct (XfcePanelPlugin *panel_plugin)
{
XfceWindowMenuPlugin *plugin = XFCE_WINDOW_MENU_PLUGIN (panel_plugin);
/* show the button */
gtk_widget_show (plugin->button);
gtk_widget_show (plugin->icon);
}
static void
window_menu_plugin_free_data (XfcePanelPlugin *panel_plugin)
{
XfceWindowMenuPlugin *plugin = XFCE_WINDOW_MENU_PLUGIN (panel_plugin);
/* release the xfconf channel */
if (G_LIKELY (plugin->channel))
g_object_unref (G_OBJECT (plugin->channel));
/* shutdown xfconf */
xfconf_shutdown ();
}
static void
window_menu_plugin_screen_position_changed (XfcePanelPlugin *panel_plugin,
gint position)
{
XfceWindowMenuPlugin *plugin = XFCE_WINDOW_MENU_PLUGIN (panel_plugin);
/* set the arrow direction if the arrow is visible */
if (!GTK_WIDGET_VISIBLE (plugin->icon))
xfce_arrow_button_set_arrow_type (XFCE_ARROW_BUTTON (plugin->button),
xfce_panel_plugin_arrow_type (panel_plugin));
}
static gboolean
window_menu_plugin_size_changed (XfcePanelPlugin *panel_plugin,
gint size)
{
XfceWindowMenuPlugin *plugin = XFCE_WINDOW_MENU_PLUGIN (panel_plugin);
/* let the panel handle the plugin size if the icon is visible */
if (GTK_WIDGET_VISIBLE (plugin->icon))
return FALSE;
/* set the size of the arrow button */
if (xfce_panel_plugin_get_orientation (panel_plugin) ==
GTK_ORIENTATION_HORIZONTAL)
gtk_widget_set_size_request (GTK_WIDGET (plugin), ARROW_BUTTON_SIZE, -1);
else
gtk_widget_set_size_request (GTK_WIDGET (plugin), -1, ARROW_BUTTON_SIZE);
return TRUE;
}
static void
window_menu_plugin_configure_plugin (XfcePanelPlugin *panel_plugin)
{
//XfceWindowMenuPlugin *plugin = XFCE_WINDOW_MENU_PLUGIN (panel_plugin);
GtkBuilder *builder;
GObject *dialog, *object;
builder = gtk_builder_new ();
if (gtk_builder_add_from_string (builder, windowmenu_dialog_glade,
windowmenu_dialog_glade_length, NULL))
{
dialog = gtk_builder_get_object (builder, "dialog");
g_object_weak_ref (G_OBJECT (dialog), (GWeakNotify) g_object_unref, builder);
xfce_panel_plugin_take_window (panel_plugin, GTK_WINDOW (dialog));
xfce_panel_plugin_block_menu (panel_plugin);
g_object_weak_ref (G_OBJECT (dialog), (GWeakNotify)
xfce_panel_plugin_unblock_menu, panel_plugin);
object = gtk_builder_get_object (builder, "close-button");
g_signal_connect_swapped (G_OBJECT (object), "clicked",
G_CALLBACK (gtk_widget_destroy), dialog);
gtk_widget_show (GTK_WIDGET (dialog));
}
else
{
/* release the builder */
g_object_unref (G_OBJECT (builder));
}
}
static void
window_menu_plugin_active_window_changed (WnckScreen *screen,
WnckWindow *previous_window,
XfceWindowMenuPlugin *plugin)
{
WnckWindow *window;
GdkPixbuf *pixbuf;
XfceScaledImage *icon = XFCE_SCALED_IMAGE (plugin->icon);
panel_return_if_fail (XFCE_IS_WINDOW_MENU_PLUGIN (plugin));
panel_return_if_fail (XFCE_IS_SCALED_IMAGE (icon));
panel_return_if_fail (WNCK_IS_SCREEN (screen));
panel_return_if_fail (plugin->screen == screen);
/* only do this when the icon is visible */
if (GTK_WIDGET_VISIBLE (icon))
{
/* get the window icon and set the tooltip */
window = wnck_screen_get_active_window (screen);
if (G_LIKELY (window != NULL))
{
pixbuf = wnck_window_get_icon (window);
gtk_widget_set_tooltip_text (GTK_WIDGET (icon),
wnck_window_get_name (window));
if (G_LIKELY (pixbuf != NULL))
xfce_scaled_image_set_from_pixbuf (icon, pixbuf);
else
xfce_scaled_image_set_from_icon_name (icon, GTK_STOCK_MISSING_IMAGE);
}
else
{
/* desktop is shown right now */
xfce_scaled_image_set_from_icon_name (icon, "user-desktop");
gtk_widget_set_tooltip_text (GTK_WIDGET (icon), _("Desktop"));
}
}
}
static void
window_menu_plugin_window_state_changed (WnckWindow *window,
WnckWindowState changed_mask,
WnckWindowState new_state,
XfceWindowMenuPlugin *plugin)
{
panel_return_if_fail (XFCE_IS_WINDOW_MENU_PLUGIN (plugin));
panel_return_if_fail (WNCK_IS_WINDOW (window));
panel_return_if_fail (plugin->enable_urgency_notify);
/* only response to urgency changes and urgency notify is enabled */
if (!PANEL_HAS_FLAG (changed_mask, URGENT_FLAGS))
return;
/* update the blinking state */
if (PANEL_HAS_FLAG (new_state, URGENT_FLAGS))
plugin->urgent_windows++;
else
plugin->urgent_windows--;
/* check if we need to change the button */
if (plugin->urgent_windows == 1)
xfce_arrow_button_set_blinking (XFCE_ARROW_BUTTON (plugin->button), TRUE);
else if (plugin->urgent_windows == 0)
xfce_arrow_button_set_blinking (XFCE_ARROW_BUTTON (plugin->button), FALSE);
}
static void
window_menu_plugin_window_opened (WnckScreen *screen,
WnckWindow *window,
XfceWindowMenuPlugin *plugin)
{
panel_return_if_fail (XFCE_IS_WINDOW_MENU_PLUGIN (plugin));
panel_return_if_fail (WNCK_IS_WINDOW (window));
panel_return_if_fail (WNCK_IS_SCREEN (screen));
panel_return_if_fail (plugin->screen == screen);
/* leave when urgency notify is disabled */
if (!plugin->enable_urgency_notify)
return;
/* monitor the window's state */
g_signal_connect (G_OBJECT (window), "state-changed",
G_CALLBACK (window_menu_plugin_window_state_changed), plugin);
/* check if the window needs attention */
if (wnck_window_needs_attention (window))
window_menu_plugin_window_state_changed (window, URGENT_FLAGS,
URGENT_FLAGS, plugin);
}
static void
window_menu_plugin_window_closed (WnckScreen *screen,
WnckWindow *window,
XfceWindowMenuPlugin *plugin)
{
panel_return_if_fail (XFCE_IS_WINDOW_MENU_PLUGIN (plugin));
panel_return_if_fail (WNCK_IS_WINDOW (window));
panel_return_if_fail (WNCK_IS_SCREEN (screen));
panel_return_if_fail (plugin->screen == screen);
/* leave when urgency notify is disabled */
if (!plugin->enable_urgency_notify)
return;
/* check if we need to update the urgency counter */
if (wnck_window_needs_attention (window))
window_menu_plugin_window_state_changed (window, URGENT_FLAGS,
0, plugin);
}
static gboolean
window_menu_plugin_button_press_event (GtkWidget *button,
GdkEventButton *event,
XfceWindowMenuPlugin *plugin)
{
GtkWidget *menu;
panel_return_val_if_fail (XFCE_IS_WINDOW_MENU_PLUGIN (plugin), FALSE);
panel_return_val_if_fail (XFCE_IS_ARROW_BUTTON (button), FALSE);
panel_return_val_if_fail (GTK_IS_TOGGLE_BUTTON (button), FALSE);
/* only respond to a normal button 1 press */
if (event->type != GDK_BUTTON_PRESS
|| event->button != 1)
return FALSE;
/* activate the toggle button */
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
/* popup the menu */
menu = window_menu_plugin_menu_new (plugin);
gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
xfce_panel_plugin_position_menu, plugin,
event->button, event->time);
return TRUE;
}
static void
window_menu_plugin_menu_workspace_item_active (GtkWidget *mi,
WnckWorkspace *workspace)
{
panel_return_if_fail (WNCK_IS_WORKSPACE (workspace));
/* activate the workspace */
wnck_workspace_activate (workspace, gtk_get_current_event_time ());
}
static GtkWidget *
window_menu_plugin_menu_workspace_item_new (WnckWorkspace *workspace,
PangoFontDescription *bold)
{
const gchar *name;
gchar *utf8 = NULL, *name_num = NULL;
GtkWidget *mi, *label;
panel_return_val_if_fail (WNCK_IS_WORKSPACE (workspace), NULL);
/* try to get an utf-8 valid name */
name = wnck_workspace_get_name (workspace);
if (IS_STRING (name) && !g_utf8_validate (name, -1, NULL))
name = utf8 = g_locale_to_utf8 (name, -1, NULL, NULL, NULL);
/* generate a workspace name */
if (!IS_STRING (name))
name = name_num = g_strdup_printf (_("Workspace %d"),
wnck_workspace_get_number (workspace) + 1);
/* create the menu item */
mi = gtk_menu_item_new_with_label (name);
g_signal_connect (G_OBJECT (mi), "activate",
G_CALLBACK (window_menu_plugin_menu_workspace_item_active), workspace);
/* modify the label */
label = gtk_bin_get_child (GTK_BIN (mi));
panel_return_val_if_fail (GTK_IS_LABEL (label), NULL);
gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_MIDDLE);
gtk_label_set_max_width_chars (GTK_LABEL (label), 24);
/* modify the label font if needed */
if (bold != NULL)
gtk_widget_modify_font (label, bold);
/* cleanup */
g_free (utf8);
g_free (name_num);
return mi;
}
static void
window_menu_plugin_menu_actions_selection_done (GtkWidget *action_menu,
GtkMenuShell *menu)
{
panel_return_if_fail (GTK_IS_MENU_SHELL (menu));
panel_return_if_fail (WNCK_IS_ACTION_MENU (action_menu));
/* destroy the action menu */
gtk_widget_destroy (action_menu);
/* deactive the window list menu */
gtk_menu_shell_cancel (menu);
}
static gboolean
window_menu_plugin_menu_window_item_activate (GtkWidget *mi,
GdkEventButton *event,
WnckWindow *window)
{
WnckWorkspace *workspace;
GtkWidget *menu;
panel_return_val_if_fail (WNCK_IS_WINDOW (window), FALSE);
panel_return_val_if_fail (GTK_IS_MENU_ITEM (mi), FALSE);
panel_return_val_if_fail (GTK_IS_MENU_SHELL (mi->parent), FALSE);
/* onyl respond to a button releases */
if (event->type != GDK_BUTTON_RELEASE)
return FALSE;
if (event->button == 1)
{
/* go to workspace and activate window */
workspace = wnck_window_get_workspace (window);
if (workspace != NULL)
wnck_workspace_activate (workspace, event->time - 1);
wnck_window_activate (window, event->time);
}
else if (event->button == 2)
{
/* active the window (bring it to this workspace) */
wnck_window_activate (window, event->time);
}
else if (event->button == 3)
{
/* popup the window action menu */
menu = wnck_action_menu_new (window);
g_signal_connect (G_OBJECT (menu), "selection-done",
G_CALLBACK (window_menu_plugin_menu_actions_selection_done),
gtk_widget_get_parent (mi));
gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL,
NULL, event->button, event->time);
return TRUE;
}
return FALSE;
}
static GtkWidget *
window_menu_plugin_menu_window_item_new (WnckWindow *window,
PangoFontDescription *italic,
PangoFontDescription *bold)
{
const gchar *name, *tooltip;
gchar *utf8 = NULL;
gchar *decorated = NULL;
GtkWidget *mi, *label, *image;
GdkPixbuf *pixbuf, *lucent = NULL;
panel_return_val_if_fail (WNCK_IS_WINDOW (window), NULL);
/* try to get an utf-8 valid name */
name = wnck_window_get_name (window);
if (IS_STRING (name) && !g_utf8_validate (name, -1, NULL))
name = utf8 = g_locale_to_utf8 (name, -1, NULL, NULL, NULL);
/* make sure we have atleast something in the name */
if (!IS_STRING (name))
name = "?";
/* store the tooltip text */
tooltip = name;
/* create a decorated name for the label */
if (wnck_window_is_shaded (window))
name = decorated = g_strdup_printf ("=%s=", name);
else if (wnck_window_is_minimized (window))
name = decorated = g_strdup_printf ("[%s]", name);
/* create the menu item */
mi = gtk_image_menu_item_new_with_label (name);
gtk_widget_set_tooltip_text (mi, tooltip);
g_object_set_qdata (G_OBJECT (mi), window_quark, window);
g_signal_connect (G_OBJECT (mi), "button-release-event",
G_CALLBACK (window_menu_plugin_menu_window_item_activate), window);
/* cleanup */
g_free (utf8);
g_free (decorated);
/* modify the label */
label = gtk_bin_get_child (GTK_BIN (mi));
panel_return_val_if_fail (GTK_IS_LABEL (label), NULL);
gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_MIDDLE);
gtk_label_set_max_width_chars (GTK_LABEL (label), 24);
/* modify the label font if needed */
if (wnck_window_is_active (window))
gtk_widget_modify_font (label, italic);
else if (wnck_window_or_transient_needs_attention (window))
gtk_widget_modify_font (label, bold);
/* get the window mini icon */
pixbuf = wnck_window_get_mini_icon (window);
if (pixbuf != NULL)
{
/* dimm the icon if the window is minimized */
if (wnck_window_is_minimized (window))
pixbuf = lucent = exo_gdk_pixbuf_lucent (pixbuf, 50);
/* set the menu item label */
image = gtk_image_new_from_pixbuf (pixbuf);
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (mi), image);
gtk_widget_show (image);
/* release */
if (lucent != NULL)
g_object_unref (G_OBJECT (lucent));
}
return mi;
}
static void
window_menu_plugin_menu_selection_done (GtkWidget *menu,
GtkWidget *button)
{
panel_return_if_fail (GTK_IS_TOGGLE_BUTTON (button));
panel_return_if_fail (GTK_IS_MENU (menu));
/* destroy the menu */
gtk_widget_destroy (menu);
/* deactivate the toggle button */
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), FALSE);
}
static gboolean
window_menu_plugin_menu_key_press_event (GtkWidget *menu,
GdkEventKey *event)
{
GtkWidget *mi = NULL;
GdkEventButton fake_event = { 0, };
guint modifiers;
WnckWindow *window;
panel_return_val_if_fail (GTK_IS_MENU (menu), FALSE);
/* construct an event */
switch (event->keyval)
{
case GDK_space:
case GDK_Return:
case GDK_KP_Space:
case GDK_KP_Enter:
/* active the menu item */
fake_event.button = 1;
break;
case GDK_Menu:
/* popup the window actions menu */
fake_event.button = 3;
break;
default:
return FALSE;
}
/* popdown the menu, this will also update the active item */
gtk_menu_popdown (GTK_MENU (menu));
/* get the active menu item leave when no item if found */
mi = gtk_menu_get_active (GTK_MENU (menu));
panel_return_val_if_fail (mi == NULL || GTK_IS_MENU_ITEM (mi), FALSE);
if (mi == NULL)
return FALSE;
if (fake_event.button == 1)
{
/* get the modifiers */
modifiers = event->state & gtk_accelerator_get_default_mod_mask ();
if (modifiers == GDK_SHIFT_MASK)
fake_event.button = 2;
else if (modifiers == GDK_CONTROL_MASK)
fake_event.button = 3;
}
/* complete the event */
fake_event.type = GDK_BUTTON_RELEASE;
fake_event.time = event->time;
/* try the get the window and active an item */
window = g_object_get_qdata (G_OBJECT (mi), window_quark);
if (window != NULL)
window_menu_plugin_menu_window_item_activate (mi, &fake_event, window);
else
gtk_menu_item_activate (GTK_MENU_ITEM (mi));
return FALSE;
}
static GtkWidget *
window_menu_plugin_menu_new (XfceWindowMenuPlugin *plugin)
{
GtkWidget *menu, *mi = NULL;
GList *workspaces, *lp;
GList *windows, *li;
WnckWorkspace *workspace;
WnckWorkspace *active_workspace, *window_workspace;
WnckWindow *window;
PangoFontDescription *italic, *bold;
gboolean has_items;
panel_return_val_if_fail (XFCE_IS_WINDOW_MENU_PLUGIN (plugin), NULL);
panel_return_val_if_fail (WNCK_IS_SCREEN (plugin->screen), NULL);
/* allocate pango styles */
italic = pango_font_description_from_string ("italic");
bold = pango_font_description_from_string ("bold");
/* create empty menu */
menu = gtk_menu_new ();
g_signal_connect (G_OBJECT (menu), "selection-done",
G_CALLBACK (window_menu_plugin_menu_selection_done), plugin->button);
g_signal_connect (G_OBJECT (menu), "key-press-event",
G_CALLBACK (window_menu_plugin_menu_key_press_event), plugin);
/* get all the windows, workspaces and the active workspace */
windows = wnck_screen_get_windows_stacked (plugin->screen);
workspaces = wnck_screen_get_workspaces (plugin->screen);
active_workspace = wnck_screen_get_active_workspace (plugin->screen);
for (lp = workspaces; lp != NULL; lp = lp->next)
{
workspace = WNCK_WORKSPACE (lp->data);
/* skip this workspace if we only show the active workspace,
* there are no urgent windows and this is not the active ws */
if (plugin->show_all_workspaces == FALSE
&& plugin->urgent_windows == 0
&& workspace != active_workspace)
continue;
/* show the workspace menu item */
if (plugin->show_all_workspaces || workspace == active_workspace)
{
/* create the workspace menu item and separator */
mi = window_menu_plugin_menu_workspace_item_new (workspace,
workspace == active_workspace ? bold : italic);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
gtk_widget_show (mi);
}
for (li = windows, has_items = FALSE; li != NULL; li = li->next)
{
window = WNCK_WINDOW (li->data);
/* windows we always want to skip */
if (wnck_window_is_skip_pager (window)
|| wnck_window_is_skip_tasklist (window))
continue;
/* get the window's workspace */
window_workspace = wnck_window_get_workspace (window);
/* show only windows from this workspace or pinned
* windows on the active workspace */
if (window_workspace != workspace
&& !(window_workspace == NULL
&& workspace == active_workspace))
continue;
/* filter out urgent windows on workspaces other then the
* current workspace */
if (plugin->show_all_workspaces == FALSE
&& plugin->urgent_windows > 0
&& window_workspace != active_workspace
&& !wnck_window_needs_attention (window))
continue;
if (has_items == FALSE)
{
/* in the case of urgent windows we need to add the header
* if this workspace is not the active workspace */
if (!plugin->show_all_workspaces && workspace != active_workspace)
{
mi = window_menu_plugin_menu_workspace_item_new (workspace,
workspace == active_workspace ? bold : italic);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
gtk_widget_show (mi);
}
/* add separator between the workspace and first window item */
mi = gtk_separator_menu_item_new ();
gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
gtk_widget_show (mi);
has_items = TRUE;
}
/* create the menu item */
mi = window_menu_plugin_menu_window_item_new (window, italic, bold);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
gtk_widget_show (mi);
}
if (lp->next != NULL
&& (has_items || plugin->show_all_workspaces))
{
mi = gtk_separator_menu_item_new ();
gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
gtk_widget_show (mi);
}
}
/* remove a remaining separator */
if (mi != NULL && GTK_IS_SEPARATOR_MENU_ITEM (mi))
gtk_widget_destroy (mi);
/* cleanup */
pango_font_description_free (italic);
pango_font_description_free (bold);
return menu;
}

9
plugins/windowmenu/windowmenu.desktop.in.in

@ -0,0 +1,9 @@
[Xfce Panel]
Type=X-XFCE-PanelPlugin
Encoding=UTF-8
_Name=Window Menu
_Comment=Switch between open windows using a menu
Icon=preferences-system-windows
X-XFCE-Module=windowmenu
X-XFCE-Module-Path=@libdir@/xfce4/panel-plugins
X-XFCE-External=FALSE

41
plugins/windowmenu/windowmenu.h

@ -0,0 +1,41 @@
/* $Id$ */
/*
* Copyright (C) 2009 Nick Schermer <nick@xfce.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., 59 Temple
* Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __XFCE_WINDOW_MENU_PLUGIN_H__
#define __XFCE_WINDOW_MENU_PLUGIN_H__
#include <gtk/gtk.h>
G_BEGIN_DECLS
typedef struct _XfceWindowMenuPluginClass XfceWindowMenuPluginClass;
typedef struct _XfceWindowMenuPlugin XfceWindowMenuPlugin;
#define XFCE_TYPE_WINDOW_MENU_PLUGIN (window_menu_plugin_get_type ())
#define XFCE_WINDOW_MENU_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), XFCE_TYPE_WINDOW_MENU_PLUGIN, XfceWindowMenuPlugin))
#define XFCE_WINDOW_MENU_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), XFCE_TYPE_WINDOW_MENU_PLUGIN, XfceWindowMenuPluginClass))
#define XFCE_IS_WINDOW_MENU_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), XFCE_TYPE_WINDOW_MENU_PLUGIN))
#define XFCE_IS_WINDOW_MENU_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XFCE_TYPE_WINDOW_MENU_PLUGIN))
#define XFCE_WINDOW_MENU_PLUGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), XFCE_TYPE_WINDOW_MENU_PLUGIN, XfceWindowMenuPluginClass))
GType window_menu_plugin_get_type (void) G_GNUC_CONST;
G_END_DECLS
#endif /* !__XFCE_WINDOW_MENU_PLUGIN_H__ */
Loading…
Cancel
Save