diff options
Diffstat (limited to 'mate-window-picker-applet')
-rw-r--r-- | mate-window-picker-applet/Makefile.am | 65 | ||||
-rw-r--r-- | mate-window-picker-applet/applet.c | 351 | ||||
-rw-r--r-- | mate-window-picker-applet/mate-window-picker-applet-menu.xml | 2 | ||||
-rw-r--r-- | mate-window-picker-applet/mate-window-picker-applet.schemas.in | 13 | ||||
-rw-r--r-- | mate-window-picker-applet/org.mate.panel.MateWindowPicker.mate-panel-applet.in.in | 11 | ||||
-rw-r--r-- | mate-window-picker-applet/org.mate.panel.applet.MateWindowPickerFactory.service.in | 3 | ||||
-rw-r--r-- | mate-window-picker-applet/task-item.c | 779 | ||||
-rw-r--r-- | mate-window-picker-applet/task-item.h | 72 | ||||
-rw-r--r-- | mate-window-picker-applet/task-list.c | 246 | ||||
-rw-r--r-- | mate-window-picker-applet/task-list.h | 70 | ||||
-rw-r--r-- | mate-window-picker-applet/task-title.c | 528 | ||||
-rw-r--r-- | mate-window-picker-applet/task-title.h | 66 |
12 files changed, 2206 insertions, 0 deletions
diff --git a/mate-window-picker-applet/Makefile.am b/mate-window-picker-applet/Makefile.am new file mode 100644 index 0000000..20b39bd --- /dev/null +++ b/mate-window-picker-applet/Makefile.am @@ -0,0 +1,65 @@ +libexec_PROGRAMS=mate-window-picker-applet + +PKGDATADIR = $(datadir)/mate-window-picker-applet +AM_CFLAGS=\ + $(MATEWINDOWPICKER_DEPS_CFLAGS) \ + $(GCC_FLAGS) \ + -I$(top_builddir) \ + -I$(top_srcdir) \ + -D_GNU_SOURCE \ + -DMATELOCALEDIR=\""$(datadir)/locale"\" \ + -DPKGDATADIR=\"$(PKGDATADIR)\" \ + -DMATEWINDOWPICKER_MENU_UI_DIR=\""$(xmluidir)"\" + +mate_window_picker_applet_LDADD = \ + $(MATEWINDOWPICKER_DEPS_LIBS) + +mate_window_picker_applet_SOURCES = \ + applet.c \ + task-item.c \ + task-item.h \ + task-list.c \ + task-list.h \ + task-title.c \ + task-title.h + +appletdir = $(datadir)/mate-panel/applets +applet_in_files = org.mate.panel.MateWindowPicker.mate-panel-applet.in +applet_DATA = $(applet_in_files:.mate-panel-applet.in=.mate-panel-applet) + +$(applet_in_files): $(applet_in_files).in Makefile + $(AM_V_GEN)sed \ + -e "s|\@LOCATION\@|$(APPLET_LOCATION)|" \ + $< > $@ + +org.mate.panel.MateWindowPicker.mate-panel-applet: org.mate.panel.MateWindowPicker.mate-panel-applet.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache + +APPLET_LOCATION=$(libexecdir)/mate-window-picker-applet + +servicedir = $(datadir)/dbus-1/services +service_in_files = org.mate.panel.applet.MateWindowPickerFactory.service.in +service_DATA = $(service_in_files:.service.in=.service) + +org.mate.panel.applet.MateWindowPickerFactory.service: $(service_in_files) + $(AM_V_GEN)sed \ + -e "s|\@LOCATION\@|$(APPLET_LOCATION)|" \ + $< > $@ + +schemasdir = @MATECONF_SCHEMA_FILE_DIR@ +schemas_in_files = mate-window-picker-applet.schemas.in +schemas_DATA = $(schemas_in_files:.schemas.in=.schemas) +@INTLTOOL_SCHEMAS_RULE@ + +xmluidir = $(datadir)/mate-panel/ui +xmlui_DATA = mate-window-picker-applet-menu.xml + +EXTRA_DIST = \ + org.mate.panel.MateWindowPicker.panel-applet.in.in \ + $(service_in_files) \ + $(ui_DATA) \ + $(schemas_in_files) + +CLEANFILES = $(applet_DATA) $(applet_DATA).in $(service_DATA) $(schemas_DATA) + +clean: + rm -f $(desktop_DATA) $(desktop_DATA).in $(server_DATA) $(server_DATA).in diff --git a/mate-window-picker-applet/applet.c b/mate-window-picker-applet/applet.c new file mode 100644 index 0000000..c2b33a6 --- /dev/null +++ b/mate-window-picker-applet/applet.c @@ -0,0 +1,351 @@ +/* + * Copyright (C) 2008 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * 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, see <http://www.gnu.org/licenses/>. + * + * Authored by Neil Jagdish Patel <[email protected]> + * + */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif + +#include <string.h> +#include <stdlib.h> + +#include <glib.h> +#include <glib/gi18n.h> +#include <gtk/gtk.h> + +#include <libmatewnck/libmatewnck.h> + +#include <mate-panel-applet.h> +#include <mate-panel-applet-mateconf.h> +#include <mateconf/mateconf-client.h> + +#include "task-list.h" +#include "task-title.h" + +#define SHOW_WIN_KEY "show_all_windows" + +typedef struct +{ + GtkWidget *tasks; + GtkWidget *applet; + GtkWidget *title; + +} WinPickerApp; + +static WinPickerApp *mainapp; + +static void cw_panel_background_changed (MatePanelApplet *applet, + MatePanelAppletBackgroundType type, + GdkColor *colour, + GdkPixmap *pixmap, + gpointer user_data); +static void display_about_dialog (GtkAction *action, + WinPickerApp *applet); + +static void display_prefs_dialog (GtkAction *action, + WinPickerApp *applet); + +static const GtkActionEntry window_picker_menu_actions [] = { + { "MenuPrefs", GTK_STOCK_PREFERENCES, N_("_Preferences"), + NULL, NULL, + G_CALLBACK (display_prefs_dialog) }, + { "ShowDesktopAbout", GTK_STOCK_ABOUT, N_("_About"), + NULL, NULL, + G_CALLBACK (display_about_dialog) } +}; + +static const gchar *close_window_authors [] = { + "Neil J. Patel <[email protected]>", + "Stefano Karapetsas <[email protected]>", + NULL +}; + +static void +on_show_all_windows_changed (MateConfClient *client, + guint conn_id, + MateConfEntry *entry, + gpointer data) +{ + WinPickerApp *app; + gboolean show_windows = TRUE; + + app = (WinPickerApp*)data; + + show_windows = mate_panel_applet_mateconf_get_bool (MATE_PANEL_APPLET (app->applet), + SHOW_WIN_KEY, NULL); + + g_object_set (app->tasks, "show_all_windows", show_windows, NULL); +} + +static inline void +force_no_focus_padding (GtkWidget *widget) +{ + static gboolean first_time = TRUE; + + if (first_time) + { + gtk_rc_parse_string ("\n" + " style \"na-tray-style\"\n" + " {\n" + " GtkWidget::focus-line-width=0\n" + " GtkWidget::focus-padding=0\n" + " }\n" + "\n" + " widget \"*.na-tray\" style \"na-tray-style\"\n" + "\n"); + first_time = FALSE; + } + + gtk_widget_set_name (widget, "na-tray"); +} + +static gboolean +cw_applet_fill (MatePanelApplet *applet, + const gchar *iid, + gpointer data) +{ + MatewnckScreen *screen; + WinPickerApp *app; + GtkWidget *eb, *tasks, *title; + GError *error = NULL; + gchar *key; + gchar *ui_path; + GtkActionGroup *action_group; + + if (strcmp (iid, "MateWindowPicker") != 0) + return FALSE; + + bindtextdomain (GETTEXT_PACKAGE, MATELOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + textdomain (GETTEXT_PACKAGE); + + matewnck_set_client_type (MATEWNCK_CLIENT_TYPE_PAGER); + + app = g_slice_new0 (WinPickerApp); + mainapp = app; + screen = matewnck_screen_get_default (); + + /* mateconf prefs */ + mate_panel_applet_add_preferences (applet, + "/schemas/apps/mate-window-picker-applet/prefs", + &error); + if (error) + { + g_warning ("%s", error->message); + g_error_free (error); + } + + key = mate_panel_applet_mateconf_get_full_key (applet, SHOW_WIN_KEY); + mateconf_client_notify_add (mateconf_client_get_default (), key, + on_show_all_windows_changed, app, + NULL, NULL); + g_free (key); + + app->applet = GTK_WIDGET (applet); + force_no_focus_padding (GTK_WIDGET (applet)); + gtk_container_set_border_width (GTK_CONTAINER (applet), 0); + + eb = gtk_hbox_new (FALSE, 6); + gtk_container_add (GTK_CONTAINER (applet), eb); + gtk_container_set_border_width (GTK_CONTAINER (eb), 0); + + tasks = app->tasks = task_list_get_default (); + gtk_box_pack_start (GTK_BOX (eb), tasks, FALSE, FALSE, 0); + + title = app->title = task_title_new (); + gtk_box_pack_start (GTK_BOX (eb), title, TRUE, TRUE, 0); + + gtk_widget_show_all (GTK_WIDGET (applet)); + + on_show_all_windows_changed (NULL, 0, NULL, app); + + /* Signals */ + g_signal_connect (applet, "change-background", + G_CALLBACK (cw_panel_background_changed), NULL); + + + action_group = gtk_action_group_new ("MateWindowPicker Applet Actions"); + gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE); + gtk_action_group_add_actions (action_group, + window_picker_menu_actions, + G_N_ELEMENTS (window_picker_menu_actions), + app); + ui_path = g_build_filename (MATEWINDOWPICKER_MENU_UI_DIR, "mate-window-picker-menu.xml", NULL); + mate_panel_applet_setup_menu_from_file (MATE_PANEL_APPLET (app->applet), + ui_path, action_group); + g_free (ui_path); + g_object_unref (action_group); + + mate_panel_applet_set_flags (MATE_PANEL_APPLET (applet), + MATE_PANEL_APPLET_EXPAND_MAJOR + | MATE_PANEL_APPLET_EXPAND_MINOR + | MATE_PANEL_APPLET_HAS_HANDLE); + + return TRUE; +} + +MATE_PANEL_APPLET_OUT_PROCESS_FACTORY ("MateWindowPickerFactory", + PANEL_TYPE_APPLET, + "MateWindowPicker", + cw_applet_fill, + NULL); + +static void +cw_panel_background_changed (MatePanelApplet *applet, + MatePanelAppletBackgroundType type, + GdkColor *colour, + GdkPixmap *pixmap, + gpointer user_data) +{ + GtkRcStyle *rc_style; + GtkStyle *style; + + /* reset style */ + gtk_widget_set_style (GTK_WIDGET (applet), NULL); + rc_style = gtk_rc_style_new (); + gtk_widget_modify_style (GTK_WIDGET (applet), rc_style); + gtk_rc_style_unref (rc_style); + + gtk_widget_set_style (mainapp->title, NULL); + rc_style = gtk_rc_style_new (); + gtk_widget_modify_style (mainapp->title, rc_style); + gtk_rc_style_unref (rc_style); + + switch (type) + { + case PANEL_NO_BACKGROUND: + break; + case PANEL_COLOR_BACKGROUND: + gtk_widget_modify_bg (GTK_WIDGET (applet), GTK_STATE_NORMAL, colour); + gtk_widget_modify_bg (mainapp->title, GTK_STATE_NORMAL, colour); + break; + + case PANEL_PIXMAP_BACKGROUND: + style = gtk_style_copy (GTK_WIDGET (applet)->style); + if (style->bg_pixmap[GTK_STATE_NORMAL]) + g_object_unref (style->bg_pixmap[GTK_STATE_NORMAL]); + style->bg_pixmap[GTK_STATE_NORMAL] = g_object_ref (pixmap); + gtk_widget_set_style (GTK_WIDGET (applet), style); + g_object_unref (style); + + /*style = gtk_style_copy (mainapp->title->style); + if (style->bg_pixmap[GTK_STATE_NORMAL]) + g_object_unref (style->bg_pixmap[GTK_STATE_NORMAL]); + style->bg_pixmap[GTK_STATE_NORMAL] = g_object_ref (pixmap); + gtk_widget_set_style (mainapp->title, style); + g_object_unref (style);*/ + + break; + } +} + +static void +display_about_dialog (GtkAction *action, + WinPickerApp *applet) +{ + GtkWidget *panel_about_dialog; + + panel_about_dialog = gtk_about_dialog_new (); + + g_object_set (panel_about_dialog, + "name", _("Window Picker"), + "comments", _("Window Picker"), + "version", PACKAGE_VERSION, + "authors", close_window_authors, + "logo-icon-name", "system-preferences-windows", + "copyright", "Copyright \xc2\xa9 2008 Canonical Ltd", + NULL); + + gtk_widget_show (panel_about_dialog); + + g_signal_connect (panel_about_dialog, "response", + G_CALLBACK (gtk_widget_destroy), NULL); + + + gtk_window_present (GTK_WINDOW (panel_about_dialog)); +} + +static void +on_checkbox_toggled (GtkToggleButton *check, gpointer null) +{ + gboolean is_active; + + is_active = gtk_toggle_button_get_active (check); + + mate_panel_applet_mateconf_set_bool (MATE_PANEL_APPLET (mainapp->applet), + SHOW_WIN_KEY, is_active, NULL); +} + +static void +display_prefs_dialog (GtkAction *action, + WinPickerApp *applet) +{ + GtkWidget *window, *box, *vbox, *nb, *hbox, *label, *check, *button; + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (window), _("Preferences")); + gtk_window_set_type_hint (GTK_WINDOW (window), + GDK_WINDOW_TYPE_HINT_DIALOG); + gtk_container_set_border_width (GTK_CONTAINER (window), 12); + + box = gtk_vbox_new (FALSE, 8); + gtk_container_add (GTK_CONTAINER (window), box); + + nb = gtk_notebook_new (); + g_object_set (nb, "show-tabs", FALSE, "show-border", TRUE, NULL); + gtk_box_pack_start (GTK_BOX (box), nb, TRUE, TRUE, 0); + + vbox = gtk_vbox_new (FALSE, 8); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 8); + gtk_notebook_append_page (GTK_NOTEBOOK (nb), vbox, NULL); + + check = gtk_check_button_new_with_label (_("Show windows from all workspaces")); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, TRUE, 0); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), + mate_panel_applet_mateconf_get_bool ( + MATE_PANEL_APPLET (mainapp->applet), + SHOW_WIN_KEY, NULL)); + g_signal_connect (check, "toggled", + G_CALLBACK (on_checkbox_toggled), NULL); + + check = gtk_label_new (" "); + gtk_box_pack_start (GTK_BOX (vbox), check, TRUE, TRUE, 0); + + gtk_widget_set_size_request (nb, -1, 100); + + hbox = gtk_hbox_new (FALSE, 0); + gtk_box_pack_start (GTK_BOX (box), hbox, TRUE, TRUE, 0); + + label = gtk_label_new (" "); + gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0); + + button = gtk_button_new_from_stock (GTK_STOCK_CLOSE); + gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); + + gtk_widget_show_all (window); + + g_signal_connect (window, "delete-event", + G_CALLBACK (gtk_widget_destroy), window); + + g_signal_connect (window, "destroy", + G_CALLBACK (gtk_widget_destroy), window); + g_signal_connect_swapped (button, "clicked", + G_CALLBACK (gtk_widget_destroy), window); + + gtk_window_present (GTK_WINDOW (window)); +} diff --git a/mate-window-picker-applet/mate-window-picker-applet-menu.xml b/mate-window-picker-applet/mate-window-picker-applet-menu.xml new file mode 100644 index 0000000..7649999 --- /dev/null +++ b/mate-window-picker-applet/mate-window-picker-applet-menu.xml @@ -0,0 +1,2 @@ +<menuitem name="PreferencesItem" action="MenuPrefs" /> +<menuitem name="About Item" action="MenuAbout" /> diff --git a/mate-window-picker-applet/mate-window-picker-applet.schemas.in b/mate-window-picker-applet/mate-window-picker-applet.schemas.in new file mode 100644 index 0000000..ccceb1c --- /dev/null +++ b/mate-window-picker-applet/mate-window-picker-applet.schemas.in @@ -0,0 +1,13 @@ +<mateconfschemafile> + <schemalist> + <schema> + <key>/schemas/apps/mate-window-picker-applet/prefs/show_all_windows</key> + <owner>mate-window-picker-applet</owner> + <type>bool</type> + <default>true</default> + <locale name="C"> + <short>Show windows from all workspaces.</short> + </locale> + </schema> + </schemalist> +</mateconfschemafile> diff --git a/mate-window-picker-applet/org.mate.panel.MateWindowPicker.mate-panel-applet.in.in b/mate-window-picker-applet/org.mate.panel.MateWindowPicker.mate-panel-applet.in.in new file mode 100644 index 0000000..ffc4b98 --- /dev/null +++ b/mate-window-picker-applet/org.mate.panel.MateWindowPicker.mate-panel-applet.in.in @@ -0,0 +1,11 @@ +[Applet Factory] +Id=MateWindowPickerFactory +Location=@LOCATION@ +_Name=Window Picker Applet Factory +_Description=Window Picker + +[MateWindowPicker] +_Name=Window Picker +_Description=Window Picker +Icon=preferences-system-windows +BonoboId=OAFIID:MATE_WindowPicker diff --git a/mate-window-picker-applet/org.mate.panel.applet.MateWindowPickerFactory.service.in b/mate-window-picker-applet/org.mate.panel.applet.MateWindowPickerFactory.service.in new file mode 100644 index 0000000..f301b25 --- /dev/null +++ b/mate-window-picker-applet/org.mate.panel.applet.MateWindowPickerFactory.service.in @@ -0,0 +1,3 @@ +[D-BUS Service] +Name=org.mate.panel.applet.MateWindowPickerFactory +Exec=@LOCATION@ diff --git a/mate-window-picker-applet/task-item.c b/mate-window-picker-applet/task-item.c new file mode 100644 index 0000000..3e0dd97 --- /dev/null +++ b/mate-window-picker-applet/task-item.c @@ -0,0 +1,779 @@ +/* + * Copyright (C) 2008 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * 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, see <http://www.gnu.org/licenses/>. + * + * Authored by Jason Smith <[email protected]> + * + */ + +#include "task-item.h" +#include "task-list.h" + +#include <math.h> +#include <glib/gi18n.h> +#include <cairo/cairo.h> + +G_DEFINE_TYPE (TaskItem, task_item, GTK_TYPE_EVENT_BOX); + +#define TASK_ITEM_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\ + TASK_TYPE_ITEM, \ + TaskItemPrivate)) + +#define DEFAULT_TASK_ITEM_HEIGHT 24; +#define DEFAULT_TASK_ITEM_WIDTH 28 + +struct _TaskItemPrivate +{ + MatewnckWindow *window; + MatewnckScreen *screen; + GdkPixbuf *pixbuf; + GdkRectangle area; + + GTimeVal urgent_time; + guint timer; + gboolean mouse_over; +}; + +enum { + TASK_ITEM_CLOSED_SIGNAL, + LAST_SIGNAL +}; + +/* D&D stuff */ +static const GtkTargetEntry drop_types[] = +{ + { "STRING", 0, 0 }, + { "text/plain", 0, 0}, + { "text/uri-list", 0, 0} +}; +static const gint n_drop_types = G_N_ELEMENTS(drop_types); + +static guint task_item_signals[LAST_SIGNAL] = { 0 }; + +static void +update_hints (TaskItem *item) +{ + GtkWidget *parent; + GtkWidget *widget; + MatewnckWindow *window; + gint x, y, x1, y1; + + widget = GTK_WIDGET (item); + window = item->priv->window; + /* Skip problems */ + if (!MATEWNCK_IS_WINDOW (window)) return; + if (!GTK_IS_WIDGET (widget)) return; + + /* Skip invisible windows */ + if (!GTK_WIDGET_VISIBLE (widget)) return; + + x = y = 0; + + /* Recursively compute the button's coordinates */ + for (parent = widget; parent; parent = parent->parent) + { + if (parent->parent) + { + x += parent->allocation.x; + y += parent->allocation.y; + } + else + { + x1 = y1 = 0; + if (GDK_IS_WINDOW (parent->window)) + gdk_window_get_origin (parent->window, &x1, &y1); + x += x1; y += y1; + break; + } + } + + /* Set the minimize hint for the window */ + matewnck_window_set_icon_geometry (window, x, y, + widget->allocation.width, + widget->allocation.height); +} + +static gboolean +on_task_item_button_released (GtkWidget *widget, + GdkEventButton *event, + TaskItem *item) +{ + MatewnckWindow *window; + MatewnckScreen *screen; + MatewnckWorkspace *workspace; + TaskItemPrivate *priv; + + g_return_val_if_fail (TASK_IS_ITEM (item), TRUE); + + priv = item->priv; + window = priv->window; + + g_return_val_if_fail (MATEWNCK_IS_WINDOW (window), TRUE); + + screen = priv->screen; + workspace = matewnck_window_get_workspace (window); + + if (event->button == 1) + { + + if (MATEWNCK_IS_WORKSPACE (workspace) && workspace != matewnck_screen_get_active_workspace (screen)) + { + matewnck_workspace_activate (workspace, GDK_CURRENT_TIME); + } + if (matewnck_window_is_active (window)) + { + matewnck_window_minimize (window); + } + else + { + matewnck_window_activate (window, GDK_CURRENT_TIME); + } + } + return TRUE; +} + +static void +task_item_set_visibility (TaskItem *item) +{ + MatewnckScreen *screen; + MatewnckWindow *window; + MatewnckWorkspace *workspace; + + g_return_if_fail (TASK_IS_ITEM (item)); + + TaskItemPrivate *priv = item->priv; + + if (!MATEWNCK_IS_WINDOW (priv->window)) + { + gtk_widget_hide (GTK_WIDGET (item)); + return; + } + + window = priv->window; + + screen = priv->screen; + workspace = matewnck_screen_get_active_workspace (screen); + + gboolean show_all = task_list_get_show_all_windows (TASK_LIST (task_list_get_default ())); + gboolean show_window = FALSE; + + if (!matewnck_window_is_skip_tasklist (window)) + { + if (matewnck_workspace_is_virtual (workspace)) + { + show_window = matewnck_window_is_in_viewport (window, workspace); + } + else + { + show_window = matewnck_window_is_on_workspace (window, workspace); + } + show_window = show_window || show_all; + } + + if (show_window) + { + gtk_widget_show (GTK_WIDGET (item)); + } + else + { + gtk_widget_hide (GTK_WIDGET (item)); + } +} + +static void +task_item_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + /* Candidate for terrible hack of the year award */ + requisition->width = DEFAULT_TASK_ITEM_WIDTH; + requisition->height = DEFAULT_TASK_ITEM_HEIGHT; +} + +static GdkPixbuf * +task_item_sized_pixbuf_for_window (TaskItem *item, + MatewnckWindow *window, + gint size) +{ + GdkPixbuf *pbuf = NULL; + + g_return_val_if_fail (MATEWNCK_IS_WINDOW (window), NULL); + + if (matewnck_window_has_icon_name (window)) + { + const gchar *icon_name = matewnck_window_get_icon_name (window); + GtkIconTheme *icon_theme = gtk_icon_theme_get_default (); + + if (gtk_icon_theme_has_icon (icon_theme, icon_name)) + { + GdkPixbuf *internal = gtk_icon_theme_load_icon (icon_theme, + icon_name, + size, + GTK_ICON_LOOKUP_FORCE_SIZE, + NULL); + pbuf = gdk_pixbuf_copy (internal); + g_object_unref (internal); + } + } + + if (!pbuf) + { + pbuf = gdk_pixbuf_copy (matewnck_window_get_icon (item->priv->window)); + } + + gint width = gdk_pixbuf_get_width (pbuf); + gint height = gdk_pixbuf_get_height (pbuf); + + if (MAX (width, height) != size) + { + gdouble scale = (gdouble) size / (gdouble) MAX (width, height); + + GdkPixbuf *tmp = pbuf; + pbuf = gdk_pixbuf_scale_simple (tmp, (gint) (width * scale), (gint) (height * scale), GDK_INTERP_HYPER); + + g_object_unref (tmp); + } + + return pbuf; +} +static gboolean +task_item_expose_event (GtkWidget *widget, + GdkEventExpose *event) +{ + cairo_t *cr; + TaskItem *item; + GdkRectangle area; + TaskItemPrivate *priv; + GdkPixbuf *desat; + GdkPixbuf *pbuf; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (TASK_IS_ITEM (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + item = TASK_ITEM (widget); + priv = item->priv; + + g_return_val_if_fail (MATEWNCK_IS_WINDOW (priv->window), FALSE); + + area = priv->area; + cr = gdk_cairo_create (event->window); + + pbuf = priv->pixbuf; + desat = NULL; + + gint size = MIN (area.height, area.width); + gboolean active = matewnck_window_is_active (priv->window); + gboolean attention = matewnck_window_or_transient_needs_attention (priv->window); + + if (GDK_IS_PIXBUF (pbuf) && + gdk_pixbuf_get_width (pbuf) != size && + gdk_pixbuf_get_height (pbuf) != size) + { + g_object_unref (pbuf); + pbuf = NULL; + } + + if (active) + { + cairo_rectangle (cr, area.x + .5, area.y - 4, area.width - 1, area.height + 8); + cairo_set_source_rgba (cr, .8, .8, .8, .2); + cairo_fill_preserve (cr); + + cairo_set_line_width (cr, 1); + cairo_set_source_rgba (cr, .8, .8, .8, .4); + cairo_stroke (cr); + } + + if (!pbuf) + { + pbuf = priv->pixbuf = task_item_sized_pixbuf_for_window (item, priv->window, size); + } + + if (active || priv->mouse_over || attention) + { + gdk_cairo_set_source_pixbuf (cr, + pbuf, + (area.x + (area.width - gdk_pixbuf_get_width (pbuf)) / 2), + (area.y + (area.height - gdk_pixbuf_get_height (pbuf)) / 2)); + } + else + { + desat = gdk_pixbuf_new (GDK_COLORSPACE_RGB, + TRUE, + gdk_pixbuf_get_bits_per_sample (pbuf), + gdk_pixbuf_get_width (pbuf), + gdk_pixbuf_get_height (pbuf)); + + if (desat) + { + gdk_pixbuf_saturate_and_pixelate (pbuf, + desat, + 0, + FALSE); + } + else /* just paint the colored version as a fallback */ + { + desat = pbuf; + } + gdk_cairo_set_source_pixbuf (cr, + desat, + (area.x + (area.width - gdk_pixbuf_get_width (desat)) / 2), + (area.y + (area.height - gdk_pixbuf_get_height (desat)) / 2)); + } + if (!priv->mouse_over && attention) /* urgent */ + { + GTimeVal current_time; + g_get_current_time (¤t_time); + + gdouble ms = (current_time.tv_sec - priv->urgent_time.tv_sec) * 1000 + + (current_time.tv_usec - priv->urgent_time.tv_usec) / 1000; + + gdouble alpha = .66 + (cos (3.15 * ms / 600) / 3); + cairo_paint_with_alpha (cr, alpha); + } + else if (priv->mouse_over || active) /* focused */ + { + cairo_paint (cr); + } + else /* not focused */ + { + cairo_paint_with_alpha (cr, .65); + } + + if (GDK_IS_PIXBUF (desat)) + g_object_unref (desat); + + cairo_destroy (cr); + + return FALSE; +} + +static void +on_size_allocate (GtkWidget *widget, + GtkAllocation *allocation, + TaskItem *item) +{ + TaskItemPrivate *priv; + + if (allocation->width != allocation->height + 6) + gtk_widget_set_size_request (widget, allocation->height + 6, -1); + + g_return_if_fail (TASK_IS_ITEM (item)); + + priv = item->priv; + priv->area.x = allocation->x; + priv->area.y = allocation->y; + priv->area.width = allocation->width; + priv->area.height = allocation->height; + + update_hints (item); +} + +static gboolean +on_button_pressed (GtkWidget *button, + GdkEventButton *event, + TaskItem *item) +{ + MatewnckWindow *window; + g_return_val_if_fail (TASK_IS_ITEM (item), FALSE); + window = item->priv->window; + g_return_val_if_fail (MATEWNCK_IS_WINDOW (window), FALSE); + + if (event->button == 3) + { + GtkWidget *menu = matewnck_action_menu_new (window); + gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, + event->button, event->time); + return TRUE; + } + + return FALSE; +} + +static gboolean +on_query_tooltip (GtkWidget *widget, + gint x, gint y, + gboolean keyboard_mode, + GtkTooltip *tooltip, + TaskItem *item) +{ + MatewnckWindow *window = item->priv->window; + g_return_val_if_fail (MATEWNCK_IS_WINDOW (window), FALSE); + + gtk_tooltip_set_text (tooltip, matewnck_window_get_name(window)); + gtk_tooltip_set_icon (tooltip, matewnck_window_get_icon (window)); + + return TRUE; +} + +static gboolean +on_enter_notify (GtkWidget *widget, + GdkEventCrossing *event, + TaskItem *item) +{ + g_return_val_if_fail (TASK_IS_ITEM (item), FALSE); + + item->priv->mouse_over = TRUE; + gtk_widget_queue_draw (widget); + + return FALSE; +} + +static gboolean +on_leave_notify (GtkWidget *widget, + GdkEventCrossing *event, + TaskItem *item) +{ + g_return_val_if_fail (TASK_IS_ITEM (item), FALSE); + + item->priv->mouse_over = FALSE; + gtk_widget_queue_draw (widget); + + return FALSE; +} + +static gboolean +on_blink (TaskItem *item) +{ + g_return_val_if_fail (TASK_IS_ITEM (item), FALSE); + + gtk_widget_queue_draw (GTK_WIDGET (item)); + + if (matewnck_window_or_transient_needs_attention (item->priv->window)) + { + return TRUE; + } + else + { + item->priv->timer = 0; + return FALSE; + } +} + +static void +on_window_state_changed (MatewnckWindow *window, + MatewnckWindowState changed_mask, + MatewnckWindowState new_state, + TaskItem *item) +{ + g_return_if_fail (MATEWNCK_IS_WINDOW (window)); + g_return_if_fail (TASK_IS_ITEM (item)); + + TaskItemPrivate *priv = item->priv; + + if (new_state & MATEWNCK_WINDOW_STATE_URGENT && !priv->timer) + { + priv->timer = g_timeout_add (30, (GSourceFunc)on_blink, item); + g_get_current_time (&priv->urgent_time); + } + + task_item_set_visibility (item); +} + +static void +on_window_workspace_changed (MatewnckWindow *window, TaskItem *item) +{ + g_return_if_fail (TASK_IS_ITEM (item)); + + task_item_set_visibility (item); +} + +static void on_window_icon_changed (MatewnckWindow *window, TaskItem *item) +{ + TaskItemPrivate *priv; + + g_return_if_fail (TASK_IS_ITEM (item)); + + priv = item->priv; + + if (GDK_IS_PIXBUF (priv->pixbuf)) + { + g_object_unref (priv->pixbuf); + priv->pixbuf = NULL; + } + + gtk_widget_queue_draw (GTK_WIDGET (item)); +} + +static void +on_screen_active_window_changed (MatewnckScreen *screen, + MatewnckWindow *old_window, + TaskItem *item) +{ + MatewnckWindow *window; + TaskItemPrivate *priv; + + g_return_if_fail (TASK_IS_ITEM (item)); + + priv = item->priv; + window = priv->window; + + g_return_if_fail (MATEWNCK_IS_WINDOW (window)); + + if ((MATEWNCK_IS_WINDOW (old_window) && window == old_window) || + window == matewnck_screen_get_active_window (screen)) + { + /* queue a draw to reflect that we are [no longer] the active window */ + gtk_widget_queue_draw (GTK_WIDGET (item)); + } +} + +static void +on_screen_active_workspace_changed (MatewnckScreen *screen, + MatewnckWorkspace *old_workspace, + TaskItem *item) +{ + g_return_if_fail (TASK_IS_ITEM (item)); + + task_item_set_visibility (item); +} + +static void +on_screen_active_viewport_changed (MatewnckScreen *screen, + TaskItem *item) +{ + g_return_if_fail (TASK_IS_ITEM (item)); + + task_item_set_visibility (item); +} + +static void +on_screen_window_closed (MatewnckScreen *screen, + MatewnckWindow *window, + TaskItem *item) +{ + TaskItemPrivate *priv; + + g_return_if_fail (TASK_IS_ITEM (item)); + priv = item->priv; + g_return_if_fail (MATEWNCK_IS_WINDOW (priv->window)); + + if (priv->window == window) + { + g_signal_handlers_disconnect_by_func (screen, G_CALLBACK (on_screen_window_closed), item); + g_signal_handlers_disconnect_by_func (screen, G_CALLBACK (on_screen_active_window_changed), item); + g_signal_handlers_disconnect_by_func (screen, G_CALLBACK (on_screen_active_workspace_changed), item); + g_signal_handlers_disconnect_by_func (screen, G_CALLBACK (on_screen_window_closed), item); + g_signal_handlers_disconnect_by_func (window, G_CALLBACK (on_window_workspace_changed), item); + g_signal_handlers_disconnect_by_func (window, G_CALLBACK (on_window_state_changed), item); + + g_signal_emit (G_OBJECT (item), task_item_signals[TASK_ITEM_CLOSED_SIGNAL], 0); + } +} + +static gboolean +activate_window (GtkWidget *widget) +{ + gint active; + TaskItemPrivate *priv; + + g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); + g_return_val_if_fail (TASK_IS_ITEM (widget), FALSE); + + priv = TASK_ITEM (widget)->priv; + + g_return_val_if_fail (MATEWNCK_IS_WINDOW (priv->window), FALSE); + + active = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), "drag-true")); + + if (active) + { + MatewnckWindow *window; + + window = priv->window; + if (MATEWNCK_IS_WINDOW (window)) + matewnck_window_activate (window, time (NULL)); + } + + g_object_set_data (G_OBJECT (widget), "drag-true", GINT_TO_POINTER (0)); + + return FALSE; +} + +static void +on_drag_leave (GtkWidget *item, + GdkDragContext *context, + guint time) +{ + g_object_set_data (G_OBJECT (item), "drag-true", GINT_TO_POINTER (0)); +} + +static gboolean +on_drag_motion (GtkWidget *item, + GdkDragContext *context, + gint x, + gint y, + guint t) +{ + gint active; + + active = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item), "drag-true")); + + if (!active) + { + g_object_set_data (G_OBJECT (item), "drag-true", GINT_TO_POINTER (1)); + + g_timeout_add (1000, (GSourceFunc)activate_window, item); + } + + return FALSE; +} + +static void +task_item_setup_atk (TaskItem *item) +{ + TaskItemPrivate *priv; + GtkWidget *widget; + AtkObject *atk; + MatewnckWindow *window; + + g_return_if_fail (TASK_IS_ITEM (item)); + + widget = GTK_WIDGET (item); + priv = item->priv; + window = priv->window; + + g_return_if_fail (MATEWNCK_IS_WINDOW (window)); + + atk = gtk_widget_get_accessible (widget); + atk_object_set_name (atk, _("Window Task Button")); + atk_object_set_description (atk, matewnck_window_get_name (window)); + atk_object_set_role (atk, ATK_ROLE_PUSH_BUTTON); +} + +static void +task_item_finalize (GObject *object) +{ + TaskItemPrivate *priv; + priv = TASK_ITEM_GET_PRIVATE (object); + + /* remove timer */ + if (priv->timer) + { + g_source_remove (priv->timer); + } + + if (GDK_IS_PIXBUF (priv->pixbuf)) + { + g_object_unref (priv->pixbuf); + } + + G_OBJECT_CLASS (task_item_parent_class)->finalize (object); +} + +static void +task_item_class_init (TaskItemClass *klass) +{ + GObjectClass *obj_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + obj_class->finalize = task_item_finalize; + widget_class->expose_event = task_item_expose_event; + widget_class->size_request = task_item_size_request; + + g_type_class_add_private (obj_class, sizeof (TaskItemPrivate)); + + task_item_signals [TASK_ITEM_CLOSED_SIGNAL] = + g_signal_new ("task-item-closed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (TaskItemClass, itemclosed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); +} + +static void +task_item_init (TaskItem *item) +{ + TaskItemPrivate *priv; + priv = item->priv = TASK_ITEM_GET_PRIVATE (item); + + priv->timer = 0; +} + +GtkWidget * +task_item_new (MatewnckWindow *window) +{ + GtkWidget *item = NULL; + TaskItem *task; + TaskItemPrivate *priv; + MatewnckScreen *screen; + + g_return_val_if_fail (MATEWNCK_IS_WINDOW (window), item); + + item = g_object_new (TASK_TYPE_ITEM, + "has-tooltip", TRUE, + "visible-window", FALSE, + "above-child", TRUE, + NULL); + + gtk_widget_add_events (item, GDK_ALL_EVENTS_MASK); + gtk_container_set_border_width (GTK_CONTAINER (item), 0); + + task = TASK_ITEM (item); + priv = task->priv; + priv->window = window; + + screen = matewnck_window_get_screen (window); + priv->screen = screen; + + gtk_drag_dest_set (item, + GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP, + drop_types, n_drop_types, + GDK_ACTION_COPY); + gtk_drag_dest_add_uri_targets (item); + gtk_drag_dest_add_text_targets (item); + g_signal_connect (item, "drag-motion", + G_CALLBACK (on_drag_motion), NULL); + g_signal_connect (item, "drag-leave", + G_CALLBACK (on_drag_leave), NULL); + + g_signal_connect (screen, "viewports-changed", + G_CALLBACK (on_screen_active_viewport_changed), item); + g_signal_connect (screen, "active-window-changed", + G_CALLBACK (on_screen_active_window_changed), item); + g_signal_connect (screen, "active-workspace-changed", + G_CALLBACK (on_screen_active_workspace_changed), item); + g_signal_connect (screen, "window-closed", + G_CALLBACK (on_screen_window_closed), item); + + g_signal_connect (window, "workspace-changed", + G_CALLBACK (on_window_workspace_changed), item); + g_signal_connect (window, "state-changed", + G_CALLBACK (on_window_state_changed), item); + g_signal_connect (window, "icon-changed", + G_CALLBACK (on_window_icon_changed), item); + + g_signal_connect (item, "button-release-event", + G_CALLBACK (on_task_item_button_released), item); + g_signal_connect (item, "button-press-event", + G_CALLBACK (on_button_pressed), item); + g_signal_connect (item, "size-allocate", + G_CALLBACK (on_size_allocate), item); + g_signal_connect (item, "query-tooltip", + G_CALLBACK (on_query_tooltip), item); + g_signal_connect (item, "enter-notify-event", + G_CALLBACK (on_enter_notify), item); + g_signal_connect (item, "leave-notify-event", + G_CALLBACK (on_leave_notify), item); + g_signal_connect (item, "drag-motion", + G_CALLBACK (on_drag_motion), item); + g_signal_connect (item, "drag-leave", + G_CALLBACK (on_drag_leave), item); + + task_item_set_visibility (task); + task_item_setup_atk (task); + + return item; +} diff --git a/mate-window-picker-applet/task-item.h b/mate-window-picker-applet/task-item.h new file mode 100644 index 0000000..bf6ce38 --- /dev/null +++ b/mate-window-picker-applet/task-item.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2008 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * 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, see <http://www.gnu.org/licenses/>. + * + * Authored by: Neil Jagdish Patel <[email protected]> + * Jason Smith <[email protected]> + * + */ + +#ifndef _TASK_ITEM_H_ +#define _TASK_ITEM_H_ + +#include <glib.h> +#include <gtk/gtk.h> +#include <libmatewnck/libmatewnck.h> + +#define TASK_TYPE_ITEM (task_item_get_type ()) + +#define TASK_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),\ + TASK_TYPE_ITEM, TaskItem)) + +#define TASK_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\ + TASK_TYPE_ITEM, TaskItemClass)) + +#define TASK_IS_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),\ + TASK_TYPE_ITEM)) + +#define TASK_IS_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),\ + TASK_TYPE_ITEM)) + +#define TASK_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\ + TASK_TYPE_ITEM, TaskItemClass)) + +typedef struct _TaskItem TaskItem; +typedef struct _TaskItemClass TaskItemClass; +typedef struct _TaskItemPrivate TaskItemPrivate; + +struct _TaskItem +{ + GtkEventBox parent; + + TaskItemPrivate *priv; +}; + +struct _TaskItemClass +{ + GtkEventBoxClass parent_class; + + void (* itemclosed) (TaskItem *item); +}; + +GType task_item_get_type (void) G_GNUC_CONST; + +GtkWidget * task_item_new (MatewnckWindow *window); + +GtkWidget * task_item_get_default (void); + +gboolean task_item_get_desktop_visible (TaskItem *item); + +#endif /* _TASK_ITEM_H_ */ + diff --git a/mate-window-picker-applet/task-list.c b/mate-window-picker-applet/task-list.c new file mode 100644 index 0000000..43c0d5d --- /dev/null +++ b/mate-window-picker-applet/task-list.c @@ -0,0 +1,246 @@ +/* + * Copyright (C) 2008 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * 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, see <http://www.gnu.org/licenses/>. + * + * Authored by Neil Jagdish Patel <[email protected]> + * + */ + +#include "task-list.h" +#include "task-item.h" + +#include <libmatewnck/libmatewnck.h> + +G_DEFINE_TYPE (TaskList, task_list, GTK_TYPE_HBOX); + +#define TASK_LIST_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\ + TASK_TYPE_LIST, \ + TaskListPrivate)) + +struct _TaskListPrivate +{ + MatewnckScreen *screen; + GHashTable *win_table; + guint timer; + guint counter; + + gboolean show_all_windows; +}; + +enum +{ + PROP_0, + + PROP_SHOW_ALL_WINDOWS +}; + +static void +task_list_set_show_all_windows (TaskList *list, gboolean show_all_windows) +{ + TaskListPrivate *priv = list->priv; + + priv->show_all_windows = show_all_windows; + + g_debug ("Show all windows: %s", show_all_windows ? "true" : "false"); +} + +static void +on_task_item_closed (TaskItem *item, + TaskList *list) +{ + gtk_container_remove (GTK_CONTAINER (list), + GTK_WIDGET (item)); + gtk_widget_destroy (GTK_WIDGET (item)); +} + +static void +on_window_opened (MatewnckScreen *screen, + MatewnckWindow *window, + TaskList *list) +{ + TaskListPrivate *priv; + MatewnckWindowType type; + + g_return_if_fail (TASK_IS_LIST (list)); + priv = list->priv; + + type = matewnck_window_get_window_type (window); + + if (type == MATEWNCK_WINDOW_DESKTOP + || type == MATEWNCK_WINDOW_DOCK + || type == MATEWNCK_WINDOW_SPLASHSCREEN + || type == MATEWNCK_WINDOW_MENU) + return; + + GtkWidget *item = task_item_new (window); + + if (item) + { + gtk_box_pack_start (GTK_BOX (list), item, FALSE, FALSE, 0); + g_signal_connect (TASK_ITEM (item), "task-item-closed", + G_CALLBACK (on_task_item_closed), list); + } +} + +/* GObject stuff */ +static void +task_list_finalize (GObject *object) +{ + TaskListPrivate *priv; + + priv = TASK_LIST_GET_PRIVATE (object); + + /* Remove the blink timer */ + if (priv->timer) g_source_remove (priv->timer); + + G_OBJECT_CLASS (task_list_parent_class)->finalize (object); +} + +static void +task_list_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + TaskList *list = TASK_LIST (object); + TaskListPrivate *priv; + + g_return_if_fail (TASK_IS_LIST (list)); + priv = list->priv; + + switch (prop_id) + { + case PROP_SHOW_ALL_WINDOWS: + g_value_set_boolean (value, priv->show_all_windows); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +task_list_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + TaskList *list = TASK_LIST (object); + TaskListPrivate *priv; + + g_return_if_fail (TASK_IS_LIST (list)); + priv = list->priv; + + switch (prop_id) + { + case PROP_SHOW_ALL_WINDOWS: + task_list_set_show_all_windows (list, g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +task_list_class_init (TaskListClass *klass) +{ + GObjectClass *obj_class = G_OBJECT_CLASS (klass); + + obj_class->finalize = task_list_finalize; + obj_class->set_property = task_list_set_property; + obj_class->get_property = task_list_get_property; + + g_object_class_install_property (obj_class, + PROP_SHOW_ALL_WINDOWS, + g_param_spec_boolean ("show_all_windows", + "Show All Windows", + "Show windows from all workspaces", + TRUE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + g_type_class_add_private (obj_class, sizeof (TaskListPrivate)); +} + +static void +task_list_init (TaskList *list) +{ + TaskListPrivate *priv; + + priv = list->priv = TASK_LIST_GET_PRIVATE (list); + + priv->screen = matewnck_screen_get_default (); + + priv->win_table = g_hash_table_new (NULL, NULL); + + /* No blink timer */ + priv->timer = 0; + + gtk_container_set_border_width (GTK_CONTAINER (list), 0); + + g_signal_connect (priv->screen, "window-opened", + G_CALLBACK (on_window_opened), list); +} + +GtkWidget * +task_list_new (void) + +{ + GtkWidget *list = NULL; + + list = g_object_new (TASK_TYPE_LIST, + "homogeneous", FALSE, + "spacing", 0, + NULL); + + return list; +} + +GtkWidget * +task_list_get_default (void) +{ + static GtkWidget *list = NULL; + + if (!list) + list = task_list_new (); + + return list; +} + +gboolean +task_list_get_desktop_visible (TaskList *list) +{ + GList *windows, *w; + gboolean all_minimised = TRUE; + + g_return_val_if_fail (TASK_IS_LIST (list), TRUE); + + windows = matewnck_screen_get_windows (list->priv->screen); + for (w = windows; w; w = w->next) + { + MatewnckWindow *window; + + window = w->data; + + if (MATEWNCK_IS_WINDOW (window) && !matewnck_window_is_minimized (window)) + all_minimised = FALSE; + } + + return all_minimised; +} + +gboolean +task_list_get_show_all_windows (TaskList *list) +{ + return list->priv->show_all_windows; +} + diff --git a/mate-window-picker-applet/task-list.h b/mate-window-picker-applet/task-list.h new file mode 100644 index 0000000..87698ba --- /dev/null +++ b/mate-window-picker-applet/task-list.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2008 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * 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, see <http://www.gnu.org/licenses/>. + * + * Authored by Neil Jagdish Patel <[email protected]> + * + */ + +#ifndef _TASK_LIST_H_ +#define _TASK_LIST_H_ + +#include <glib.h> +#include <gtk/gtk.h> + +#define TASK_TYPE_LIST (task_list_get_type ()) + +#define TASK_LIST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),\ + TASK_TYPE_LIST, TaskList)) + +#define TASK_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\ + TASK_TYPE_LIST, TaskListClass)) + +#define TASK_IS_LIST(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),\ + TASK_TYPE_LIST)) + +#define TASK_IS_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),\ + TASK_TYPE_LIST)) + +#define TASK_LIST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\ + TASK_TYPE_LIST, TaskListClass)) + +typedef struct _TaskList TaskList; +typedef struct _TaskListClass TaskListClass; +typedef struct _TaskListPrivate TaskListPrivate; + +struct _TaskList +{ + GtkHBox parent; + + TaskListPrivate *priv; +}; + +struct _TaskListClass +{ + GtkHBoxClass parent_class; +}; + +GType task_list_get_type (void) G_GNUC_CONST; + +GtkWidget * task_list_new (void); + +GtkWidget * task_list_get_default (void); + +gboolean task_list_get_desktop_visible (TaskList *list); + +gboolean task_list_get_show_all_windows (TaskList *list); + +#endif /* _TASK_LIST_H_ */ + diff --git a/mate-window-picker-applet/task-title.c b/mate-window-picker-applet/task-title.c new file mode 100644 index 0000000..4795559 --- /dev/null +++ b/mate-window-picker-applet/task-title.c @@ -0,0 +1,528 @@ +/* + * Copyright (C) 2008 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * 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, see <http://www.gnu.org/licenses/>. + * + * Authored by Neil Jagdish Patel <[email protected]> + * + */ + +#include "task-title.h" + +#include <libmatewnck/libmatewnck.h> +#include <mate-panel-applet.h> +#include <mate-panel-applet-mateconf.h> + +#include <mateconf/mateconf.h> +#include <mateconf/mateconf-client.h> + +#include "task-list.h" + +G_DEFINE_TYPE (TaskTitle, task_title, GTK_TYPE_EVENT_BOX); + +#define TASK_TITLE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\ + TASK_TYPE_TITLE, \ + TaskTitlePrivate)) + +#define LOGOUT "mate-session-save --kill --gui" +#define SHOW_HOME_TITLE_KEY "/apps/window-picker-applet/show_home_title" + +struct _TaskTitlePrivate +{ + MatewnckScreen *screen; + MatewnckWindow *window; + GtkWidget *align; + GtkWidget *box; + GtkWidget *label; + GtkWidget *button; + GtkWidget *button_image; + GdkPixbuf *quit_icon; + + gboolean show_home_title; + gboolean mouse_in_close_button; +}; + +static void disconnect_window (TaskTitle *title); + +static gboolean +on_close_clicked (GtkButton *button, + GdkEventButton *event, + TaskTitle *title) +{ + TaskTitlePrivate *priv; + MatewnckWindow *window; + + g_return_val_if_fail (TASK_IS_TITLE (title), FALSE); + priv = title->priv; + + if (event->button != 1 || !priv->mouse_in_close_button) + return FALSE; + + window = matewnck_screen_get_active_window (priv->screen); + + if (!MATEWNCK_IS_WINDOW (window) + || matewnck_window_get_window_type (window) == MATEWNCK_WINDOW_DESKTOP) + { + gdk_spawn_command_line_on_screen (gdk_screen_get_default (), + LOGOUT, NULL); + } + else + { + if (priv->window == window) + disconnect_window (title); + matewnck_window_close (window, GDK_CURRENT_TIME); + } + gtk_widget_queue_draw (GTK_WIDGET (title)); + + return TRUE; +} + +static gboolean +on_enter_notify (GtkWidget *widget, + GdkEventCrossing *event, + TaskTitle *title) +{ + g_return_val_if_fail (TASK_IS_TITLE (title), FALSE); + + title->priv->mouse_in_close_button = TRUE; + gtk_widget_queue_draw (widget); + + return FALSE; +} + +static gboolean +on_leave_notify (GtkWidget *widget, + GdkEventCrossing *event, + TaskTitle *title) +{ + g_return_val_if_fail (TASK_IS_TITLE (title), FALSE); + + title->priv->mouse_in_close_button = FALSE; + gtk_widget_queue_draw (widget); + + return FALSE; +} + +static gboolean +on_button_expose (GtkWidget *widget, + GdkEventExpose *event, + TaskTitle *title) +{ + g_return_val_if_fail (TASK_IS_TITLE (title), FALSE); + + TaskTitlePrivate *priv; + priv = title->priv; + + if (priv->mouse_in_close_button) + { + GtkStyle *style = gtk_widget_get_style (widget); + gtk_paint_box (style, + event->window, + GTK_STATE_PRELIGHT, + GTK_SHADOW_NONE, + NULL, + NULL, + NULL, + event->area.x, + event->area.y + 2, + event->area.width, + event->area.height - 4); + } + return FALSE; +} + +static void +on_name_changed (MatewnckWindow *window, TaskTitle *title) +{ + TaskTitlePrivate *priv; + + g_return_if_fail (TASK_IS_TITLE (title)); + g_return_if_fail (MATEWNCK_IS_WINDOW (window)); + + priv = title->priv; + if (priv->window != window) + return; + + gtk_label_set_text (GTK_LABEL (title->priv->label), + matewnck_window_get_name (window)); + gtk_widget_set_tooltip_text (GTK_WIDGET (title), + matewnck_window_get_name (window)); + gtk_widget_queue_draw (GTK_WIDGET (title)); +} + + +static void +on_icon_changed (MatewnckWindow *window, TaskTitle *title) +{ + TaskTitlePrivate *priv; + + g_return_if_fail (TASK_IS_TITLE (title)); + g_return_if_fail (MATEWNCK_IS_WINDOW (window)); + + priv = title->priv; + if (priv->window != window) + return; + + gtk_widget_queue_draw (GTK_WIDGET (title)); +} + +static void +on_state_changed (MatewnckWindow *window, + MatewnckWindowState changed_mask, + MatewnckWindowState new_state, + TaskTitle *title) +{ + TaskTitlePrivate *priv; + + g_return_if_fail (TASK_IS_TITLE (title)); + g_return_if_fail (MATEWNCK_IS_WINDOW (window)); + + priv = title->priv; + if (priv->window != window) + return; + + if (matewnck_window_is_maximized (window)) + { + gtk_widget_set_state (GTK_WIDGET (title), GTK_STATE_ACTIVE); + gtk_widget_show (priv->box); + } + else + { + gtk_widget_set_state (GTK_WIDGET (title), GTK_STATE_NORMAL); + gtk_widget_hide (priv->box); + } +} + +static void +disconnect_window (TaskTitle *title) +{ + TaskTitlePrivate *priv = title->priv; + if (!priv->window) + return; + g_signal_handlers_disconnect_by_func (priv->window, on_name_changed, title); + g_signal_handlers_disconnect_by_func (priv->window, on_icon_changed, title); + g_signal_handlers_disconnect_by_func (priv->window, on_state_changed, title); + priv->window = NULL; +} + +static void +on_active_window_changed (MatewnckScreen *screen, + MatewnckWindow *old_window, + TaskTitle *title) +{ + TaskTitlePrivate *priv; + MatewnckWindow *act_window; + MatewnckWindowType type = MATEWNCK_WINDOW_NORMAL; + + g_return_if_fail (TASK_IS_TITLE (title)); + priv = title->priv; + + act_window = matewnck_screen_get_active_window (screen); + if (act_window) + type = matewnck_window_get_window_type (act_window); + + if (MATEWNCK_IS_WINDOW (act_window) + && matewnck_window_is_skip_tasklist (act_window) + && type != MATEWNCK_WINDOW_DESKTOP) + return; + + if (type == MATEWNCK_WINDOW_DOCK + || type == MATEWNCK_WINDOW_SPLASHSCREEN + || type == MATEWNCK_WINDOW_MENU) + return; + + disconnect_window (title); + + if (!MATEWNCK_IS_WINDOW (act_window) + || matewnck_window_get_window_type (act_window) == MATEWNCK_WINDOW_DESKTOP) + { + if (priv->show_home_title) + { + gtk_label_set_text (GTK_LABEL (priv->label), _("Home")); + gtk_image_set_from_pixbuf (GTK_IMAGE (priv->button_image), + priv->quit_icon); + gtk_widget_set_tooltip_text (priv->button, + _("Log off, switch user, lock screen or power " + "down the computer")); + gtk_widget_set_tooltip_text (GTK_WIDGET (title), + _("Home")); gtk_widget_show (priv->box); + } + else + { + gtk_widget_set_state (GTK_WIDGET (title), GTK_STATE_NORMAL); + gtk_widget_set_tooltip_text (priv->button, NULL); + gtk_widget_set_tooltip_text (GTK_WIDGET (title), NULL); + gtk_widget_hide (priv->box); + } + } + else + { + gtk_label_set_text (GTK_LABEL (priv->label), + matewnck_window_get_name (act_window)); + gtk_image_set_from_stock (GTK_IMAGE (priv->button_image), + GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU); + + gtk_widget_set_tooltip_text (GTK_WIDGET (title), + matewnck_window_get_name (act_window)); + gtk_widget_set_tooltip_text (priv->button, _("Close window")); + + g_signal_connect (act_window, "name-changed", + G_CALLBACK (on_name_changed), title); + g_signal_connect (act_window, "icon-changed", + G_CALLBACK (on_icon_changed), title); + g_signal_connect_after (act_window, "state-changed", + G_CALLBACK (on_state_changed), title); + gtk_widget_show (priv->box); + priv->window = act_window; + } + + if (MATEWNCK_IS_WINDOW (act_window) + && !matewnck_window_is_maximized (act_window) + && (priv->show_home_title ? type != MATEWNCK_WINDOW_DESKTOP : 1)) + { + gtk_widget_set_state (GTK_WIDGET (title), GTK_STATE_NORMAL); + gtk_widget_hide (priv->box); + } + else if (!MATEWNCK_IS_WINDOW (act_window)) + { + if (task_list_get_desktop_visible (TASK_LIST (task_list_get_default ())) + && priv->show_home_title) + { + gtk_label_set_text (GTK_LABEL (priv->label), _("Home")); + gtk_image_set_from_pixbuf (GTK_IMAGE (priv->button_image), + priv->quit_icon); + gtk_widget_set_tooltip_text (priv->button, + _("Log off, switch user, lock screen or power " + "down the computer")); + gtk_widget_set_tooltip_text (GTK_WIDGET (title), + _("Home")); + gtk_widget_show (priv->box); + } + else + { + gtk_widget_set_state (GTK_WIDGET (title), GTK_STATE_NORMAL); + gtk_widget_set_tooltip_text (priv->button, NULL); + gtk_widget_set_tooltip_text (GTK_WIDGET (title), NULL); + gtk_widget_hide (priv->box); + } + } + else + gtk_widget_set_state (GTK_WIDGET (title), GTK_STATE_ACTIVE); + + gtk_widget_queue_draw (GTK_WIDGET (title)); +} + +static gboolean +on_button_release (GtkWidget *title, GdkEventButton *event) +{ + TaskTitlePrivate *priv; + MatewnckWindow *window; + GtkWidget *menu; + + g_return_val_if_fail (TASK_IS_TITLE (title), FALSE); + priv = TASK_TITLE_GET_PRIVATE (title); + + window = matewnck_screen_get_active_window (priv->screen); + + g_return_val_if_fail (MATEWNCK_IS_WINDOW (window), FALSE); + + if (event->button == 3) + { + if (matewnck_window_get_window_type (window) != MATEWNCK_WINDOW_DESKTOP) + { + menu = matewnck_action_menu_new (window); + gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, + event->button, event->time); + return TRUE; + } + } + else if (event->button == 1) + { + if (event->type == GDK_2BUTTON_PRESS && matewnck_window_is_maximized (window)) + { + matewnck_window_unmaximize (window); + } + } + + return FALSE; +} + + +static gboolean +on_expose (GtkWidget *eb, GdkEventExpose *event) +{ + + if (eb->state == GTK_STATE_ACTIVE) + gtk_paint_box (eb->style, eb->window, + eb->state, GTK_SHADOW_NONE, + NULL, eb, "button", + eb->allocation.x, eb->allocation.y, + eb->allocation.width, eb->allocation.height); + + + gtk_container_propagate_expose (GTK_CONTAINER (eb), + gtk_bin_get_child (GTK_BIN (eb)), + event); + return TRUE; +} + +/* GObject stuff */ +static void +task_title_finalize (GObject *object) +{ + TaskTitlePrivate *priv; + + priv = TASK_TITLE_GET_PRIVATE (object); + disconnect_window (TASK_TITLE (object)); + + g_object_unref (G_OBJECT (priv->quit_icon)); + + G_OBJECT_CLASS (task_title_parent_class)->finalize (object); +} + +static void +task_title_class_init (TaskTitleClass *klass) +{ + GObjectClass *obj_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *wid_class = GTK_WIDGET_CLASS (klass); + + obj_class->finalize = task_title_finalize; + wid_class->expose_event = on_expose; + + g_type_class_add_private (obj_class, sizeof (TaskTitlePrivate)); +} + +static void +task_title_init (TaskTitle *title) +{ + TaskTitlePrivate *priv; + MateConfClient *client; + GdkScreen *gdkscreen; + GtkIconTheme *theme; + GtkSettings *settings; + GdkPixbuf *pixbuf; + AtkObject *atk; + int width, height; + + priv = title->priv = TASK_TITLE_GET_PRIVATE (title); + + priv->screen = matewnck_screen_get_default (); + priv->window = NULL; + + client = mateconf_client_get_default (); + priv->show_home_title = mateconf_client_get_bool (client, + SHOW_HOME_TITLE_KEY, + NULL); + g_object_unref (client); + + gtk_widget_add_events (GTK_WIDGET (title), GDK_ALL_EVENTS_MASK); + + priv->align = gtk_alignment_new (0.0, 0.5, 1.0, 1.0); + gtk_alignment_set_padding (GTK_ALIGNMENT (priv->align), + 0, 0, 6, 6); + gtk_container_add (GTK_CONTAINER (title), priv->align); + + priv->box = gtk_hbox_new (FALSE, 2); + gtk_container_add (GTK_CONTAINER (priv->align), priv->box); + gtk_widget_set_no_show_all (priv->box, TRUE); + gtk_widget_show (priv->box); + + priv->label = gtk_label_new (_("Home")); + gtk_label_set_ellipsize (GTK_LABEL (priv->label), PANGO_ELLIPSIZE_END); + gtk_misc_set_alignment (GTK_MISC (priv->label), 0.0, 0.5); + + PangoAttrList *attr_list = pango_attr_list_new (); + PangoAttribute *attr = pango_attr_weight_new (PANGO_WEIGHT_BOLD); + pango_attr_list_insert (attr_list, attr); + gtk_label_set_attributes (GTK_LABEL (priv->label), attr_list); + + gtk_box_pack_start (GTK_BOX (priv->box), priv->label, TRUE, TRUE, 0); + gtk_widget_show (priv->label); + + priv->button = g_object_new (GTK_TYPE_EVENT_BOX, + "visible-window", FALSE, + "above-child", TRUE, + NULL); + gtk_box_pack_start (GTK_BOX (priv->box), priv->button, FALSE, FALSE, 0); + gtk_widget_show (priv->button); + + atk = gtk_widget_get_accessible (priv->button); + atk_object_set_name (atk, _("Close")); + atk_object_set_description (atk, _("Close current window.")); + atk_object_set_role (atk, ATK_ROLE_PUSH_BUTTON); + + g_signal_connect (priv->button, "button-release-event", + G_CALLBACK (on_close_clicked), title); + g_signal_connect (priv->button, "enter-notify-event", + G_CALLBACK (on_enter_notify), title); + g_signal_connect (priv->button, "leave-notify-event", + G_CALLBACK (on_leave_notify), title); + g_signal_connect (priv->button, "expose-event", + G_CALLBACK (on_button_expose), title); + + /* Load the quit icon. We have to do this in such a god-forsaken way + because of http://bugzilla.mate.org/show_bug.cgi?id=581359 and the + fact that we support as far back as GTK+ 2.12 (which never passes + FORCE_SIZE in GtkImage). The only way to guarantee icon size is to + load and scale it ourselves. We don't do this for all the other icons + in the source just because we know that this icon doesn't come in the + size we want. */ + gdkscreen = gtk_widget_get_screen (GTK_WIDGET (title)); + theme = gtk_icon_theme_get_for_screen (gdkscreen); + settings = gtk_settings_get_for_screen (gdkscreen); + if (!gtk_icon_size_lookup_for_settings (settings, GTK_ICON_SIZE_MENU, +&width, &height)) + width = height = 16; + width = MIN(width, height); + pixbuf = gtk_icon_theme_load_icon (theme, "mate-logout", width, 0, NULL); + priv->quit_icon = gdk_pixbuf_scale_simple (pixbuf, width, width, + GDK_INTERP_BILINEAR); + g_object_unref (G_OBJECT (pixbuf)); + + priv->button_image = gtk_image_new_from_pixbuf (priv->quit_icon); + gtk_container_add (GTK_CONTAINER (priv->button), priv->button_image); + gtk_widget_show (priv->button_image); + + gtk_widget_set_tooltip_text (priv->button, + _("Log off, switch user, lock screen or power " + "down the computer")); + gtk_widget_set_tooltip_text (GTK_WIDGET (title), _("Home")); + + if (priv->show_home_title) + gtk_widget_set_state (GTK_WIDGET (title), GTK_STATE_ACTIVE); + else + gtk_widget_hide (priv->box); + + + gtk_widget_add_events (GTK_WIDGET (title), GDK_ALL_EVENTS_MASK); + + g_signal_connect (priv->screen, "active-window-changed", + G_CALLBACK (on_active_window_changed), title); + g_signal_connect (title, "button-press-event", + G_CALLBACK (on_button_release), NULL); +} + +GtkWidget * +task_title_new (void) + +{ + GtkWidget *title = NULL; + + title = g_object_new (TASK_TYPE_TITLE, + "border-width", 0, + "name", "tasklist-button", + "visible-window", FALSE, + NULL); + + return title; +} diff --git a/mate-window-picker-applet/task-title.h b/mate-window-picker-applet/task-title.h new file mode 100644 index 0000000..0a1d7ec --- /dev/null +++ b/mate-window-picker-applet/task-title.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2008 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * 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, see <http://www.gnu.org/licenses/>. + * + * Authored by Neil Jagdish Patel <[email protected]> + * + */ + +#ifndef _TASK_TITLE_H_ +#define _TASK_TITLE_H_ + +#include <glib.h> +#include <glib/gi18n.h> +#include <gtk/gtk.h> + +#define TASK_TYPE_TITLE (task_title_get_type ()) + +#define TASK_TITLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),\ + TASK_TYPE_TITLE, TaskTitle)) + +#define TASK_TITLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\ + TASK_TYPE_TITLE, TaskTitleClass)) + +#define TASK_IS_TITLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),\ + TASK_TYPE_TITLE)) + +#define TASK_IS_TITLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),\ + TASK_TYPE_TITLE)) + +#define TASK_TITLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\ + TASK_TYPE_TITLE, TaskTitleClass)) + +typedef struct _TaskTitle TaskTitle; +typedef struct _TaskTitleClass TaskTitleClass; +typedef struct _TaskTitlePrivate TaskTitlePrivate; + +struct _TaskTitle +{ + GtkEventBox parent; + + TaskTitlePrivate *priv; +}; + +struct _TaskTitleClass +{ + GtkEventBoxClass parent_class; +}; + +GType task_title_get_type (void) G_GNUC_CONST; + +GtkWidget * task_title_new (void); + + +#endif /* _TASK_TITLE_H_ */ + |