All pastes #934195 Raw Edit

deskmenu-wnck.c

public c v1 · immutable
·published 2008-03-08 18:07 UTC
rendered paste body
#include <stdlib.h>#include <string.h>#include <gtk/gtk.h>#include "deskmenu-wnck.h"/* borrowed from libwnck selector.c */static GdkPixbuf *wnck_selector_dimm_icon (GdkPixbuf *pixbuf){  int x, y, pixel_stride, row_stride;  guchar *row, *pixels;  int w, h;  GdkPixbuf *dimmed;  w = gdk_pixbuf_get_width (pixbuf);  h = gdk_pixbuf_get_height (pixbuf);  if (gdk_pixbuf_get_has_alpha (pixbuf))     dimmed = gdk_pixbuf_copy (pixbuf);  else    dimmed = gdk_pixbuf_add_alpha (pixbuf, FALSE, 0, 0, 0);  pixel_stride = 4;  row = gdk_pixbuf_get_pixels (dimmed);  row_stride = gdk_pixbuf_get_rowstride (dimmed);  for (y = 0; y < h; y++)    {      pixels = row;      for (x = 0; x < w; x++)        {          pixels[3] /= 2;          pixels += pixel_stride;        }      row += row_stride;    }  return dimmed;}#define SELECTOR_MAX_WIDTH 50   /* maximum width in characters */static gintwnck_selector_get_width (GtkWidget  *widget,                         const char *text){  PangoContext *context;  PangoFontMetrics *metrics;  gint char_width;  PangoLayout *layout;  PangoRectangle natural;  gint max_width;  gint screen_width;  gint width;  gtk_widget_ensure_style (widget);  context = gtk_widget_get_pango_context (widget);  metrics = pango_context_get_metrics (context, widget->style->font_desc,                                       pango_context_get_language (context));  char_width = pango_font_metrics_get_approximate_char_width (metrics);  pango_font_metrics_unref (metrics);  max_width = PANGO_PIXELS (SELECTOR_MAX_WIDTH * char_width);  layout = gtk_widget_create_pango_layout (widget, text);  pango_layout_get_pixel_extents (layout, NULL, &natural);  g_object_unref (G_OBJECT (layout));  screen_width = gdk_screen_get_width (gtk_widget_get_screen (widget));  width = MIN (natural.width, max_width);  width = MIN (width, 3 * (screen_width / 4));  return width;}/* end borrowing */static voiddmwin_set_weight (DeskmenuWindow *dmwin, PangoWeight weight){    PangoFontDescription *font_desc;    font_desc = pango_font_description_new ();    pango_font_description_set_weight (font_desc, weight);    gtk_widget_modify_font (dmwin->label, font_desc);    pango_font_description_free (font_desc);}static voiddmwin_set_decoration (DeskmenuWindow *dmwin, gchar *ante, gchar *post){    GString *name;    gchar *namecpy, *mnemonic, *decorated_name, *unescaped;    guint i, n;    name = g_string_new (wnck_window_get_name (dmwin->window));        namecpy = g_strdup (name->str);    n = 0;    for (i = 0; i < name->len; i++)    {        if (namecpy[i] == '_')        {            g_string_insert_c (name, i+n, '_');            n++;        }    }    g_free (namecpy);    if (name->len)        mnemonic = "_";    else        mnemonic = "";    decorated_name = g_strconcat (ante, mnemonic, name->str, post, NULL);    unescaped = g_strconcat (ante, wnck_window_get_name (dmwin->window),        post, NULL);	/* begin soreau code */	char *markup;        if (wnck_window_is_minimized (dmwin->window))        {                markup = g_markup_printf_escaped ("<span foreground='#999'>%s</span>", unescaped);                gtk_label_set_markup (GTK_LABEL (dmwin->label), markup);                g_free (markup);        }else	/* end soreau code */    gtk_label_set_text_with_mnemonic (GTK_LABEL (dmwin->label), decorated_name);    gtk_widget_set_size_request (dmwin->label,        wnck_selector_get_width (dmwin->windowlist->menu, unescaped), -1);    g_string_free (name, TRUE);    g_free (decorated_name);    g_free (unescaped);}static voidtoggle_activate_window (GtkWidget  *widget,			WnckWindow *window){    guint32 timestamp;    timestamp = gtk_get_current_event_time ();/* begin soreau code */    if (wnck_window_is_active (window))    wnck_window_minimize (window);    else/* end soreau code */    wnck_window_activate (window, timestamp);}static gintdmwin_for_window (DeskmenuWindow *dmwin,                   WnckWindow *window){    if (dmwin->window == window)        return 0;    else        return -1; /* keep searching */}static voidwindow_name_changed (WnckWindow *window,                      DeskmenuWindow *dmwin){    if (wnck_window_is_minimized (window))    {        if (wnck_window_is_shaded (window))            dmwin_set_decoration (dmwin, "=", "=");        else            dmwin_set_decoration (dmwin, "[", "]");    }    else        dmwin_set_decoration (dmwin, "", "");}static voidwindow_icon_changed (WnckWindow *window,                      DeskmenuWindow* dmwin){    GdkPixbuf *pixbuf;    gboolean free_pixbuf;    pixbuf = wnck_window_get_mini_icon (window);     free_pixbuf = FALSE;        if (wnck_window_is_minimized (window))    {        pixbuf = wnck_selector_dimm_icon (pixbuf);        free_pixbuf = TRUE;    }    gtk_image_set_from_pixbuf (GTK_IMAGE (dmwin->image), pixbuf);    if (free_pixbuf)        g_object_unref (pixbuf);}static voidwindow_state_changed (WnckWindow      *window,                      WnckWindowState  changed_state,                      WnckWindowState  new_state,                      DeskmenuWindow  *dmwin){    if (changed_state        & (WNCK_WINDOW_STATE_DEMANDS_ATTENTION | WNCK_WINDOW_STATE_URGENT))    {        if (wnck_window_or_transient_needs_attention (window))            dmwin_set_weight (dmwin, PANGO_WEIGHT_BOLD);        else            dmwin_set_weight (dmwin, PANGO_WEIGHT_NORMAL);    }    if (changed_state        & (WNCK_WINDOW_STATE_MINIMIZED | WNCK_WINDOW_STATE_SHADED))        window_name_changed (window, dmwin);    if (changed_state & WNCK_WINDOW_STATE_SKIP_TASKLIST)    {        if (wnck_window_is_skip_tasklist (window))        {            gtk_widget_hide_all (dmwin->item);            gtk_widget_set_no_show_all (dmwin->item, TRUE);        }        else        {            gtk_widget_set_no_show_all (dmwin->item, FALSE);            gtk_widget_show_all (dmwin->item);        }    }}static voidwindowlist_check_empty (DeskmenuWindowlist *windowlist){    if (!windowlist->windows && !windowlist->empty_item)    {        windowlist->empty_item = gtk_menu_item_new_with_label ("None");        gtk_widget_set_sensitive (windowlist->empty_item, FALSE);        gtk_menu_shell_append (GTK_MENU_SHELL (windowlist->menu),            windowlist->empty_item);        gtk_widget_show (windowlist->empty_item);    }    else if (windowlist->empty_item)    {        gtk_widget_destroy (windowlist->empty_item);        windowlist->empty_item = NULL;    }}static DeskmenuWindow*deskmenu_windowlist_window_new (WnckWindow *window,                                DeskmenuWindowlist *windowlist){    DeskmenuWindow *dmwin;    dmwin = g_slice_new0 (DeskmenuWindow);    dmwin->window = window;    dmwin->windowlist = windowlist;    dmwin->item = gtk_image_menu_item_new ();    dmwin->label = gtk_label_new (NULL);    gtk_container_add (GTK_CONTAINER (dmwin->item), dmwin->label);    gtk_misc_set_alignment (GTK_MISC (dmwin->label), 0.0, 0.5);    gtk_label_set_ellipsize (GTK_LABEL (dmwin->label), PANGO_ELLIPSIZE_END);    dmwin->image = gtk_image_new ();    gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (dmwin->item),        dmwin->image);    g_signal_connect (G_OBJECT (dmwin->item), "activate",         G_CALLBACK (toggle_activate_window), window);    gtk_menu_shell_append (GTK_MENU_SHELL (windowlist->menu),         dmwin->item);    window_name_changed (window, dmwin);    window_icon_changed (window, dmwin);    if (wnck_window_or_transient_needs_attention (window))        dmwin_set_weight (dmwin, PANGO_WEIGHT_BOLD);    else        dmwin_set_weight (dmwin, PANGO_WEIGHT_NORMAL);    g_signal_connect (G_OBJECT (window), "name-changed",         G_CALLBACK (window_name_changed), dmwin);    g_signal_connect (G_OBJECT (window), "icon-changed",         G_CALLBACK (window_icon_changed), dmwin);    g_signal_connect (G_OBJECT (window), "state-changed",         G_CALLBACK (window_state_changed), dmwin);    gtk_widget_set_no_show_all (dmwin->item,        wnck_window_is_skip_tasklist (window));    gtk_widget_show_all (dmwin->item);    return dmwin;}static voidscreen_window_opened (WnckScreen *screen, WnckWindow *window,                      DeskmenuWindowlist *windowlist){    DeskmenuWindow *dmwin;    dmwin = deskmenu_windowlist_window_new (window, windowlist);    windowlist->windows = g_list_prepend (windowlist->windows, dmwin);    windowlist_check_empty (windowlist);}static voidscreen_window_closed (WnckScreen *screen, WnckWindow *window,                      DeskmenuWindowlist *windowlist){    DeskmenuWindow *dmwin;    GList *list;    list = g_list_find_custom (windowlist->windows, window,        (GCompareFunc) dmwin_for_window);    if (!list)        return;    dmwin = list->data;    gtk_widget_destroy (dmwin->image);    gtk_widget_destroy (dmwin->label);    gtk_widget_destroy (dmwin->item);    g_slice_free (DeskmenuWindow, dmwin);    windowlist->windows = g_list_remove (windowlist->windows, dmwin);    windowlist_check_empty (windowlist);}DeskmenuWindowlist*deskmenu_windowlist_new (void){    DeskmenuWindowlist *windowlist;    windowlist = g_slice_new0 (DeskmenuWindowlist);    windowlist->screen = wnck_screen_get_default ();    windowlist->menu = gtk_menu_new ();    g_signal_connect (G_OBJECT (windowlist->screen), "window-opened",        G_CALLBACK (screen_window_opened), windowlist);    g_signal_connect (G_OBJECT (windowlist->screen), "window-closed",        G_CALLBACK (screen_window_closed), windowlist);    windowlist_check_empty (windowlist);    return windowlist;}static voiddeskmenu_vplist_goto (GtkWidget      *widget,                      DeskmenuVplist *vplist){    guint viewport;    viewport = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (widget),         "viewport"));    guint column, row, i;    column = viewport % vplist->hsize;    if (!column)        column = vplist->hsize - 1; /* needs to be zero-indexed */    else        column--;    row = 0;    if (viewport > vplist->hsize)    {        i = 0;        while (i < (viewport - vplist->hsize))        {            i += vplist->hsize;            row++;        }    }    wnck_screen_move_viewport (vplist->screen,        column * vplist->screen_width,        row * vplist->screen_height);}static voiddeskmenu_vplist_go_direction (GtkWidget      *widget,                              DeskmenuVplist *vplist){    WnckMotionDirection direction;    direction = (WnckMotionDirection) GPOINTER_TO_UINT (g_object_get_data         (G_OBJECT (widget), "direction"));    guint x = vplist->x, y = vplist->y;    switch (direction)    {        case WNCK_MOTION_LEFT:            if (vplist->screen_width > x)                x = vplist->xmax;            else                x -= vplist->screen_width;            break;        case WNCK_MOTION_RIGHT:            if (x + vplist->screen_width > vplist->xmax)                x = 0;            else                x += vplist->screen_width;            break;        case WNCK_MOTION_UP:            if (vplist->screen_height > y)                y = vplist->ymax;            else                y -= vplist->screen_height;            break;        case WNCK_MOTION_DOWN:            if (y + vplist->screen_height > vplist->ymax)                y = 0;            else                y += vplist->screen_height;            break;        default:            g_assert_not_reached ();            break;    }    wnck_screen_move_viewport (vplist->screen, x, y);}static gbooleandeskmenu_vplist_can_move (DeskmenuVplist      *vplist,                          WnckMotionDirection  direction){    if (!vplist->wrap)    {        switch (direction)        {            case WNCK_MOTION_LEFT:                return vplist->x;            case WNCK_MOTION_RIGHT:                return (vplist->x != vplist->xmax);            case WNCK_MOTION_UP:                return vplist->y;            case WNCK_MOTION_DOWN:                return (vplist->y != vplist->ymax);            default:                break;        }    }    else    {        switch (direction)        {            case WNCK_MOTION_LEFT:            case WNCK_MOTION_RIGHT:                return (vplist->hsize > 1);            case WNCK_MOTION_UP:            case WNCK_MOTION_DOWN:                return (vplist->vsize > 1);            default:                break;        }    }    g_assert_not_reached ();}static GtkWidget*deskmenu_vplist_make_go_item (DeskmenuVplist      *vplist,                              WnckMotionDirection  direction,                              gchar               *name,                              gchar               *stock_id){    GtkWidget *item;    item = gtk_image_menu_item_new_with_mnemonic (name);    gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item),        gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_MENU));    g_object_set_data (G_OBJECT (item), "direction",        GINT_TO_POINTER (direction));    g_signal_connect (G_OBJECT (item), "activate",         G_CALLBACK (deskmenu_vplist_go_direction), vplist);    gtk_menu_shell_append (GTK_MENU_SHELL (vplist->menu), item);        return item;}guintdeskmenu_vplist_get_vpid (DeskmenuVplist *vplist){    guint column, row;    column = vplist->x / vplist->screen_width;    row = vplist->y / vplist->screen_height;        return (row * vplist->hsize + column + 1);}static voiddeskmenu_vplist_update (WnckScreen *screen, DeskmenuVplist *vplist){    guint new_count, current;    /* get dimensions */    vplist->workspace = wnck_screen_get_workspace        (vplist->screen, 0);    vplist->screen_width = wnck_screen_get_width (screen);    vplist->workspace_width = wnck_workspace_get_width        (vplist->workspace);    vplist->screen_height = wnck_screen_get_height (screen);    vplist->workspace_height = wnck_workspace_get_height        (vplist->workspace);    vplist->x = wnck_workspace_get_viewport_x (vplist->workspace);    vplist->y = wnck_workspace_get_viewport_y (vplist->workspace);    vplist->xmax = vplist->workspace_width - vplist->screen_width;    vplist->ymax = vplist->workspace_height - vplist->screen_height;    vplist->hsize = vplist->workspace_width / vplist->screen_width;    current = deskmenu_vplist_get_vpid (vplist);    vplist->vsize = vplist->workspace_height / vplist->screen_height;    new_count = vplist->hsize * vplist->vsize;    gtk_widget_hide (vplist->go_left);    gtk_widget_hide (vplist->go_right);    gtk_widget_hide (vplist->go_up);    gtk_widget_hide (vplist->go_down);    gtk_widget_set_no_show_all (vplist->go_left,        !deskmenu_vplist_can_move (vplist, WNCK_MOTION_LEFT));    gtk_widget_set_no_show_all (vplist->go_right,        !deskmenu_vplist_can_move (vplist, WNCK_MOTION_RIGHT));    gtk_widget_set_no_show_all (vplist->go_up,        !deskmenu_vplist_can_move (vplist, WNCK_MOTION_UP));    gtk_widget_set_no_show_all (vplist->go_down,        !deskmenu_vplist_can_move (vplist, WNCK_MOTION_DOWN));    GtkWidget *item;    guint i;    if (new_count > vplist->old_count)    {        gchar *text;        for (i = vplist->old_count; i < new_count; i++)        {            text = g_strdup_printf ("Viewport _%i", i + 1);            item = gtk_menu_item_new_with_mnemonic (text);            g_object_set_data (G_OBJECT (item), "viewport",                GUINT_TO_POINTER (i + 1));            g_signal_connect (G_OBJECT (item), "activate",                G_CALLBACK (deskmenu_vplist_goto), vplist);            gtk_menu_shell_append (GTK_MENU_SHELL (vplist->menu), item);            g_ptr_array_add (vplist->goto_items, item);            g_free (text);        }        vplist->old_count = new_count;    }    else if (new_count < vplist->old_count)    {        for (i = new_count; i < vplist->old_count; i++)        {            item = g_ptr_array_index (vplist->goto_items, i);            gtk_widget_destroy (item);        }        g_ptr_array_remove_range (vplist->goto_items, new_count,             vplist->old_count - new_count);        vplist->old_count = new_count;    }    if (current != vplist->old_vpid)    {        if (vplist->old_vpid && vplist->old_vpid <= new_count)        {            item = g_ptr_array_index (vplist->goto_items, vplist->old_vpid - 1);            gtk_widget_set_sensitive (item, TRUE);        }        item = g_ptr_array_index (vplist->goto_items, current - 1);        gtk_widget_set_sensitive (item, FALSE);        vplist->old_vpid = current;    }    gtk_widget_show_all (vplist->menu);        return;}DeskmenuVplist*deskmenu_vplist_new (void){    DeskmenuVplist *vplist;    vplist = g_slice_new0 (DeskmenuVplist);    vplist->screen = wnck_screen_get_default ();    vplist->menu = gtk_menu_new ();    vplist->go_left = deskmenu_vplist_make_go_item (vplist, WNCK_MOTION_LEFT,                  "Viewport _Left", GTK_STOCK_GO_BACK);    vplist->go_right = deskmenu_vplist_make_go_item (vplist, WNCK_MOTION_RIGHT,                  "Viewport _Right", GTK_STOCK_GO_FORWARD);    vplist->go_up =  deskmenu_vplist_make_go_item (vplist, WNCK_MOTION_UP,                  "Viewport _Up", GTK_STOCK_GO_UP);    vplist->go_down = deskmenu_vplist_make_go_item (vplist, WNCK_MOTION_DOWN,                  "Viewport _Down", GTK_STOCK_GO_DOWN);    gtk_menu_shell_append (GTK_MENU_SHELL (vplist->menu),         gtk_separator_menu_item_new ());    vplist->goto_items = g_ptr_array_new ();    g_signal_connect (G_OBJECT (vplist->screen), "viewports-changed",        G_CALLBACK (deskmenu_vplist_update), vplist);    return vplist;}