Skip to content
Snippets Groups Projects
tabwin.c 11.6 KiB
Newer Older
        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, 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
Olivier Fourdan's avatar
Olivier Fourdan committed
        Foundation, Inc., Inc., 51 Franklin Street, Fifth Floor, Boston,
        MA 02110-1301, USA.
Olivier Fourdan's avatar
Olivier Fourdan committed

        xfwm4    - (c) 2002-2008 Olivier Fourdan
Olivier Fourdan's avatar
Olivier Fourdan committed
#include "config.h"
#ifndef WIN_ICON_SIZE
#define WIN_ICON_SIZE 48
#endif

#ifndef WIN_ICON_BORDER
#define WIN_ICON_BORDER 5
#endif
#include <glib.h>
#include <gdk/gdk.h>
#include <gtk/gtk.h>
Olivier Fourdan's avatar
Olivier Fourdan committed
#include <libxfce4util/libxfce4util.h>
#include "inline-tabwin-icon.h"
#include "icons.h"
#include "focus.h"
static GdkColor *
get_color (GtkWidget * win, GtkStateType state_type)
{
Olivier Fourdan's avatar
Olivier Fourdan committed
    GtkStyle *style;

    g_return_val_if_fail (win != NULL, NULL);
    g_return_val_if_fail (GTK_IS_WIDGET (win), NULL);
    g_return_val_if_fail (GTK_WIDGET_REALIZED (win), NULL);

    style = gtk_rc_get_style (win);
    if (!style)
    {
        style = gtk_widget_get_style (win);
    }
    if (!style)
    {
        style = gtk_widget_get_default_style ();
    return (&style->bg[state_type]);
}

static gboolean
Olivier Fourdan's avatar
Olivier Fourdan committed
paint_selected (GtkWidget * w, GdkEventExpose * event, gpointer data)
Olivier Fourdan's avatar
Olivier Fourdan committed
    gtk_paint_box (w->style, w->window,
        GTK_STATE_SELECTED,
        GTK_SHADOW_IN,
        NULL, w, "box",
Olivier Fourdan's avatar
Olivier Fourdan committed
        w->allocation.x - WIN_ICON_BORDER,
        w->allocation.y - WIN_ICON_BORDER,
        w->allocation.width + 2 * WIN_ICON_BORDER,
        w->allocation.height + 2 * WIN_ICON_BORDER);
/* Efficiency is definitely *not* the goal here! */
static gchar *
Olivier Fourdan's avatar
Olivier Fourdan committed
pretty_string (const gchar * s)
        canonical = g_ascii_strup (s, -1);
        g_strcanon (canonical, "[]()0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ", ' ');
tabwinSetLabel (Tabwin * t, gchar * class, gchar * label, int workspace)
    gchar *message;

    message = pretty_string (class);
    gtk_label_set_use_markup (GTK_LABEL (t->class), TRUE);
Olivier Fourdan's avatar
Olivier Fourdan committed
    markup = g_strconcat ("<span size=\"larger\" weight=\"bold\">", message, "</span>", NULL);
Olivier Fourdan's avatar
Olivier Fourdan committed
    gtk_label_set_markup (GTK_LABEL (t->class), markup);
    if (t->display_workspace)
    {
        message = g_strdup_printf ("[%i] - %s", workspace + 1, label);
    }
    else
    {
        message = g_strdup_printf ("%s", label);
    }
    gtk_label_set_text (GTK_LABEL (t->label), message);
Olivier Fourdan's avatar
Olivier Fourdan committed
tabwinSetSelected (Tabwin * t, GtkWidget * w)
    if (t->selected_callback)
Olivier Fourdan's avatar
Olivier Fourdan committed
        g_signal_handler_disconnect (t->current->data, t->selected_callback);
Olivier Fourdan's avatar
Olivier Fourdan committed
    t->selected_callback = g_signal_connect (G_OBJECT (w), "expose-event", G_CALLBACK (paint_selected), NULL);
Olivier Fourdan's avatar
Olivier Fourdan committed
    c = g_object_get_data (G_OBJECT (w), "client-ptr-val");

    if (FLAG_TEST (c->flags, CLIENT_FLAG_ICONIFIED))
    {
        classname = g_strdup_printf ("[ %s ]", c->class.res_class);
    }
    else
    {
        classname = g_strdup(c->class.res_class);
    }
    tabwinSetLabel (t, classname, c->name, c->win_workspace);
    g_free (classname);
Olivier Fourdan's avatar
Olivier Fourdan committed
createWindowIcon (Client * c)
{
    GdkPixbuf *icon_pixbuf;
Olivier Fourdan's avatar
Olivier Fourdan committed
    GtkWidget *icon;
Olivier Fourdan's avatar
Olivier Fourdan committed
    icon_pixbuf = getAppIcon (c->screen_info->display_info, c->window, WIN_ICON_SIZE, WIN_ICON_SIZE);
Olivier Fourdan's avatar
Olivier Fourdan committed
    icon = gtk_image_new ();
    g_object_set_data (G_OBJECT (icon), "client-ptr-val", c);
    if (icon_pixbuf)
        if (FLAG_TEST (c->flags, CLIENT_FLAG_ICONIFIED))
        {
            icon_pixbuf_stated = gdk_pixbuf_copy (icon_pixbuf);
            gdk_pixbuf_saturate_and_pixelate (icon_pixbuf, icon_pixbuf_stated, 0.25, TRUE);
            gtk_image_set_from_pixbuf (GTK_IMAGE (icon), icon_pixbuf_stated);
            g_object_unref(icon_pixbuf_stated);
        }
        else
        {
            gtk_image_set_from_pixbuf (GTK_IMAGE (icon), icon_pixbuf);
        }
        g_object_unref(icon_pixbuf);
Olivier Fourdan's avatar
Olivier Fourdan committed
        gtk_image_set_from_stock (GTK_IMAGE (icon), "gtk-missing-image", GTK_ICON_SIZE_DIALOG);
    return icon;
}

static GtkWidget *
createWindowlist (GdkScreen * scr, Client * current, Client * new, unsigned int cycle_range, Tabwin * t)
Olivier Fourdan's avatar
Olivier Fourdan committed
    ScreenInfo *screen_info;
    GdkRectangle monitor_sz;
    GtkWidget *windowlist, *icon;
    unsigned int grid_cols;
    unsigned int n_clients;
    unsigned int grid_rows;
Olivier Fourdan's avatar
Olivier Fourdan committed
    int i, packpos;
    int msx, msy;
    gint monitor;
Olivier Fourdan's avatar
Olivier Fourdan committed
    i = 0;
    packpos = 0;
Olivier Fourdan's avatar
Olivier Fourdan committed

    /* calculate the wrapping */
    n_clients = screen_info->client_count;
    g_return_val_if_fail (n_clients > 0, NULL);
    getMouseXY (screen_info, screen_info->xroot, &msx, &msy);
    monitor = find_monitor_at_point (scr, msx, msy);
    gdk_screen_get_monitor_geometry (scr, monitor, &monitor_sz);
    /* add the width of the border on each side */
Olivier Fourdan's avatar
Olivier Fourdan committed
    grid_cols = (monitor_sz.width / (WIN_ICON_SIZE + 2 * WIN_ICON_BORDER)) * 0.75;
Olivier Fourdan's avatar
Olivier Fourdan committed
    grid_rows = n_clients / grid_cols + 1;
    windowlist = gtk_table_new (grid_rows, grid_cols, FALSE);

    t->grid_cols = grid_cols;
    t->grid_rows = grid_rows;
    /* pack the client icons */
    for (c2 = current, i = 0; c2 && i < n_clients; i++, c2 = c2->next)
        if (!clientSelectMask (c2, cycle_range, WINDOW_REGULAR_FOCUSABLE))
Olivier Fourdan's avatar
Olivier Fourdan committed
        icon = createWindowIcon (c2);
        gtk_table_attach (GTK_TABLE (windowlist), GTK_WIDGET (icon),
            packpos % grid_cols, packpos % grid_cols + 1,
            packpos / grid_cols, packpos / grid_cols + 1,
            GTK_FILL, GTK_FILL, 7, 7);
        packpos++;
        t->head = g_list_append (t->head, icon);
    if (next)
    {
        tabwinSetSelected (t, next->data);
    }
tabwinCreate (GdkScreen * scr, Client * current, Client * new, unsigned int cycle_range, gboolean display_workspace)
    GtkWidget *frame;
    GtkWidget *colorbox1, *colorbox2;
Olivier Fourdan's avatar
Olivier Fourdan committed
    GtkWidget *vbox;
    GtkWidget *windowlist;
    GdkColor *color;
Olivier Fourdan's avatar
Olivier Fourdan committed
    tabwin->window = gtk_window_new (GTK_WINDOW_POPUP);
    tabwin->display_workspace = display_workspace;
Olivier Fourdan's avatar
Olivier Fourdan committed
    gtk_window_set_screen (GTK_WINDOW (tabwin->window), scr);
    gtk_widget_set_name (GTK_WIDGET (tabwin->window), "xfwm4-tabwin");
    gtk_widget_realize (GTK_WIDGET (tabwin->window));
Olivier Fourdan's avatar
Olivier Fourdan committed
    gtk_container_set_border_width (GTK_CONTAINER (tabwin->window), 0);
Olivier Fourdan's avatar
Olivier Fourdan committed
    gtk_window_set_position (GTK_WINDOW (tabwin->window), GTK_WIN_POS_CENTER_ALWAYS);
    frame = gtk_frame_new (NULL);
    gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
    gtk_container_set_border_width (GTK_CONTAINER (frame), 0);
    gtk_container_add (GTK_CONTAINER (tabwin->window), frame);

    colorbox1 = gtk_event_box_new ();
    gtk_container_add (GTK_CONTAINER (frame), colorbox1);

    colorbox2 = gtk_event_box_new ();
    gtk_container_set_border_width (GTK_CONTAINER (colorbox2), 3);
    gtk_container_add (GTK_CONTAINER (colorbox1), colorbox2);

    vbox = gtk_vbox_new (FALSE, 5);
    gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
    gtk_container_add (GTK_CONTAINER (colorbox2), vbox);
Olivier Fourdan's avatar
Olivier Fourdan committed
    gtk_label_set_use_markup (GTK_LABEL (tabwin->class), TRUE);
    gtk_label_set_justify (GTK_LABEL (tabwin->class), GTK_JUSTIFY_CENTER);
Olivier Fourdan's avatar
Olivier Fourdan committed
    gtk_box_pack_start (GTK_BOX (vbox), tabwin->class, TRUE, TRUE, 0);

    frame = gtk_frame_new (NULL);
    gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
    gtk_container_set_border_width (GTK_CONTAINER (frame), 0);
    gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);

    tabwin->label = gtk_label_new ("");
    gtk_label_set_use_markup (GTK_LABEL (tabwin->label), FALSE);
    gtk_label_set_justify (GTK_LABEL (tabwin->label), GTK_JUSTIFY_CENTER);
    gtk_box_pack_start (GTK_BOX (vbox), tabwin->label, TRUE, TRUE, 0);
Olivier Fourdan's avatar
Olivier Fourdan committed
    gtk_widget_set_size_request (GTK_WIDGET (tabwin->label), 240, -1);
    windowlist = createWindowlist (scr, current, new, cycle_range, tabwin);
Olivier Fourdan's avatar
Olivier Fourdan committed
    gtk_container_add (GTK_CONTAINER (frame), windowlist);
    color = get_color (tabwin->window, GTK_STATE_SELECTED);
    if (color)
    {
        gtk_widget_modify_bg (colorbox1, GTK_STATE_NORMAL, color);
    }

        gtk_label_set_ellipsize (GTK_LABEL (tabwin->label), PANGO_ELLIPSIZE_END);
        gtk_label_set_ellipsize (GTK_LABEL (tabwin->class), PANGO_ELLIPSIZE_END);
Olivier Fourdan's avatar
Olivier Fourdan committed
Client *
tabwinGetSelected (Tabwin * t)
{
    g_return_val_if_fail (t != NULL, NULL);

    if ((t->current) && (t->current->data))
Olivier Fourdan's avatar
Olivier Fourdan committed
    {
Olivier Fourdan's avatar
Olivier Fourdan committed
        return (Client *) g_object_get_data (G_OBJECT (t->current->data), "client-ptr-val");
Olivier Fourdan's avatar
Olivier Fourdan committed
    return NULL;
Olivier Fourdan's avatar
Olivier Fourdan committed
}

Client *
tabwinRemoveClient (Tabwin * t, Client * c)
    g_return_val_if_fail (t != NULL, NULL);

    if (!tmp)
    {
        return NULL;
    }

Olivier Fourdan's avatar
Olivier Fourdan committed
    do
    {
        if (((Client *) g_object_get_data (tmp->data, "client-ptr-val")) == c)
        {
            if (tmp == t->current)
Olivier Fourdan's avatar
Olivier Fourdan committed
                tabwinSelectNext (t);
Olivier Fourdan's avatar
Olivier Fourdan committed
            gtk_container_remove (GTK_CONTAINER (t->container), tmp->data);
            t->head = g_list_delete_link (t->head, tmp);
Olivier Fourdan's avatar
Olivier Fourdan committed
            return tabwinGetSelected (t);
Olivier Fourdan's avatar
Olivier Fourdan committed
        /* since this is a circular list, hitting head signals end, not hitting NULL */
    }
    while ((tmp) && (tmp = g_list_next (tmp)));
Olivier Fourdan's avatar
Olivier Fourdan committed

    return tabwinGetSelected (t);
Olivier Fourdan's avatar
Olivier Fourdan committed
Client *
tabwinSelectNext (Tabwin * t)
    GList *next;
    g_return_val_if_fail (t != NULL, NULL);

    next = g_list_next(t->current);
    if (!next)
    {
        next = t->head;
        g_return_val_if_fail (next != NULL, NULL);
    tabwinSetSelected (t, next->data);
    t->current = next;
Olivier Fourdan's avatar
Olivier Fourdan committed
    gtk_widget_queue_draw (t->window);

    return tabwinGetSelected (t);
Olivier Fourdan's avatar
Olivier Fourdan committed
Client *
tabwinSelectPrev (Tabwin * t)
    GList *prev;
    g_return_val_if_fail (t != NULL, NULL);

    prev = g_list_previous (t->current);
    if (!prev)
    {
        prev = g_list_last (t->head);
        g_return_val_if_fail (prev != NULL, NULL);
    tabwinSetSelected (t, prev->data);
    t->current = prev;
Olivier Fourdan's avatar
Olivier Fourdan committed
    gtk_widget_queue_draw (t->window);

    return tabwinGetSelected (t);
Client *
tabwinGetHead (Tabwin * t)
{
    g_return_val_if_fail (t != NULL, NULL);

    if ((t->head) && (t->head->data))
    {
        return (Client *) g_object_get_data (G_OBJECT (t->head->data), "client-ptr-val");
    }

    return NULL;
}

tabwinDestroy (Tabwin * t)
    g_return_if_fail (t != NULL);
        g_list_free (t->head);
    gtk_widget_destroy (t->window);