]> Dogcows Code - chaz/openbox/commitdiff
new focus cycle popup of doom
authorDana Jansens <danakj@orodu.net>
Sat, 19 May 2007 18:40:37 +0000 (18:40 +0000)
committerDana Jansens <danakj@orodu.net>
Sat, 19 May 2007 18:40:37 +0000 (18:40 +0000)
openbox/focus_cycle_popup.c [new file with mode: 0644]
openbox/focus_cycle_popup.h [new file with mode: 0644]
render/render.c
render/render.h

diff --git a/openbox/focus_cycle_popup.c b/openbox/focus_cycle_popup.c
new file mode 100644 (file)
index 0000000..dfa2ff4
--- /dev/null
@@ -0,0 +1,432 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+   focus_cycle_popup.c for the Openbox window manager
+   Copyright (c) 2006        Mikael Magnusson
+   Copyright (c) 2003-2007   Dana Jansens
+
+   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.
+
+   See the COPYING file for a copy of the GNU General Public License.
+*/
+
+#include "focus_cycle_popup.h"
+#include "popup.h"
+#include "client.h"
+#include "screen.h"
+#include "focus.h"
+#include "focus_cycle.h"
+#include "openbox.h"
+#include "window.h"
+#include "render/render.h"
+
+#include <X11/Xlib.h>
+#include <glib.h>
+
+#define ICON_SIZE 48
+#define ICON_HILITE_WIDTH 2
+
+typedef struct _ObFocusCyclePopup       ObFocusCyclePopup;
+typedef struct _ObFocusCyclePopupTarget ObFocusCyclePopupTarget;
+
+struct _ObFocusCyclePopupTarget
+{
+    ObClient *client;
+    gchar *text;
+    Window win;
+};
+
+struct _ObFocusCyclePopup
+{
+    ObWindow obwin;
+    Window bg;
+
+    Window text;
+
+    GList *targets;
+    gint n_targets;
+
+    ObFocusCyclePopupTarget *last_target;
+
+    gint maxtextw;
+
+    RrAppearance *a_bg;
+    RrAppearance *a_text;
+    RrAppearance *a_icon;
+
+    RrPixel32 *hilite_rgba;
+
+    gboolean mapped;
+};
+
+static ObFocusCyclePopup popup;
+
+static gchar *popup_get_name (ObClient *c);
+static void   popup_setup    (ObFocusCyclePopup *p,gboolean all_desktops,
+                              gboolean dock_windows, gboolean desktop_windows);
+static void   popup_render   (ObFocusCyclePopup *p, const ObClient *c);
+
+static Window create_window(Window parent, guint bwidth, gulong mask,
+                            XSetWindowAttributes *attr)
+{
+    return XCreateWindow(ob_display, parent, 0, 0, 1, 1, bwidth,
+                         RrDepth(ob_rr_inst), InputOutput,
+                         RrVisual(ob_rr_inst), mask, attr);
+}
+
+void focus_cycle_popup_startup(gboolean reconfig)
+{
+    XSetWindowAttributes attrib;
+
+    popup.obwin.type = Window_Internal;
+    popup.a_bg = RrAppearanceCopy(ob_rr_theme->osd_hilite_bg);
+    popup.a_text = RrAppearanceCopy(ob_rr_theme->osd_hilite_label);
+    popup.a_icon = RrAppearanceCopy(ob_rr_theme->a_clear_tex);
+
+    popup.a_text->surface.parent = popup.a_bg;
+    popup.a_icon->surface.parent = popup.a_bg;
+
+    popup.a_icon->texture[0].type = RR_TEXTURE_RGBA;
+
+    RrAppearanceAddTextures(popup.a_bg, 1);
+    popup.a_bg->texture[0].type = RR_TEXTURE_RGBA;
+
+    attrib.override_redirect = True;
+    attrib.border_pixel=RrColorPixel(ob_rr_theme->frame_focused_border_color);
+    popup.bg = create_window(RootWindow(ob_display, ob_screen),
+                             ob_rr_theme->fbwidth,
+                             CWOverrideRedirect | CWBorderPixel, &attrib);
+
+    popup.text = create_window(popup.bg, 0, 0, NULL);
+
+    popup.targets = NULL;
+    popup.n_targets = 0;
+    popup.last_target = NULL;
+
+    popup.hilite_rgba = NULL;
+
+    XMapWindow(ob_display, popup.text);
+
+    stacking_add(INTERNAL_AS_WINDOW(&popup));
+}
+
+void focus_cycle_popup_shutdown(gboolean reconfig)
+{
+    stacking_remove(INTERNAL_AS_WINDOW(&popup));
+
+    while(popup.targets) {
+        ObFocusCyclePopupTarget *t = popup.targets->data;
+
+        g_free(t->text);
+        XDestroyWindow(ob_display, t->win);
+
+        popup.targets = g_list_delete_link(popup.targets, popup.targets);
+    }
+
+    g_free(popup.hilite_rgba);
+
+    XDestroyWindow(ob_display, popup.text);
+    XDestroyWindow(ob_display, popup.bg);
+
+    RrAppearanceFree(popup.a_icon);
+    RrAppearanceFree(popup.a_text);
+    RrAppearanceFree(popup.a_bg);
+}
+
+static void popup_setup(ObFocusCyclePopup *p,gboolean all_desktops,
+                        gboolean dock_windows, gboolean desktop_windows)
+{
+    gint maxwidth, n;
+    GList *it;
+
+    g_assert(p->targets == NULL);
+    g_assert(p->n_targets == 0);
+
+    /* make its width to be the width of all the possible titles */
+
+    /* build a list of all the valid focus targets and measure their strings,
+       and count them */
+    maxwidth = 0;
+    n = 0;
+    for (it = g_list_last(focus_order); it; it = g_list_previous(it)) {
+        ObClient *ft = it->data;
+
+        if (focus_cycle_target_valid(ft,
+                                     all_desktops,
+                                     dock_windows,
+                                     desktop_windows))
+        {
+            ObFocusCyclePopupTarget *t = g_new(ObFocusCyclePopupTarget, 1);
+
+            t->client = ft;
+            t->text = popup_get_name(ft);
+            t->win = create_window(p->bg, 0, 0, NULL);
+
+            XMapWindow(ob_display, t->win);
+
+            /* measure */
+            p->a_text->texture[0].data.text.string = t->text;
+            maxwidth = MAX(maxwidth, RrMinWidth(p->a_text));
+
+            p->targets = g_list_prepend(p->targets, t);
+            ++n;
+        }
+    }
+
+    p->n_targets = n;
+    p->maxtextw = maxwidth;
+}
+
+static gchar *popup_get_name(ObClient *c)
+{
+    ObClient *p;
+    gchar *title = NULL;
+    const gchar *desk = NULL;
+    gchar *ret;
+
+    /* find our highest direct parent, including non-normal windows */
+    for (p = c; p->transient_for && p->transient_for != OB_TRAN_GROUP;
+         p = p->transient_for);
+
+    if (c->desktop != DESKTOP_ALL && c->desktop != screen_desktop)
+        desk = screen_desktop_names[c->desktop];
+
+    /* use the transient's parent's title/icon if we don't have one */
+    if (p != c && !strcmp("", (c->iconic ? c->icon_title : c->title)))
+        title = g_strdup(p->iconic ? p->icon_title : p->title);
+
+    if (title == NULL)
+        title = g_strdup(c->iconic ? c->icon_title : c->title);
+
+    if (desk)
+        ret = g_strdup_printf("%s [%s]", title, desk);
+    else {
+        ret = title;
+        title = NULL;
+    }
+    g_free(title);
+
+    return ret;
+}
+
+static void popup_render(ObFocusCyclePopup *p, const ObClient *c)
+{
+    gint l, t, r, b;
+    gint x, y, w, h;
+    Rect *screen_area;
+    gint icons_per_row;
+    gint icon_rows;
+    gint textx, texty, textw, texth;
+    gint iconw, iconh;
+    gint i;
+    GList *it;
+    const ObFocusCyclePopupTarget *newtarget;
+    gint newtargetx, newtargety;
+
+    /* XXX find the middle monitor? */
+    screen_area = screen_physical_area_monitor(0);
+
+    /* get the outside margins */
+    RrMargins(p->a_bg, &l, &t, &r, &b);
+    l += ob_rr_theme->paddingx;
+    r += ob_rr_theme->paddingx;
+    t += ob_rr_theme->paddingy;
+    b += ob_rr_theme->paddingy;
+
+    /* get the icons sizes */
+    iconw = ICON_SIZE - (ICON_HILITE_WIDTH + ob_rr_theme->paddingx) * 2;
+    iconh = ICON_SIZE - (ICON_HILITE_WIDTH + ob_rr_theme->paddingy) * 2;
+
+    /* get the width from the text and keep it within limits */
+    w = l + r + p->maxtextw;
+    w = MIN(w, MAX(screen_area->width/3, POPUP_WIDTH)); /* max width */
+    w = MAX(w, POPUP_WIDTH); /* min width */
+
+    /* how many icons will fit in that row? make the width fit that */
+    w -= l + r;
+    icons_per_row = w / ICON_SIZE;
+    w = icons_per_row * ICON_SIZE + l + r;
+
+    /* how many rows do we need? */
+    icon_rows = (p->n_targets-1) / icons_per_row + 1;
+
+    /* get the text dimensions */
+    textw = w - l - r;
+    texth = RrMinHeight(p->a_text);
+
+    /* find the height of the dialog */
+    h = t + b + (icon_rows * ICON_SIZE) + (ob_rr_theme->paddingy + texth);
+
+    /* get the position of the text */
+    textx = l;
+    texty = h - texth;
+
+    /* find the position for the popup (include the outer borders) */
+    x = screen_area->x + (screen_area->width -
+                          (w + ob_rr_theme->fbwidth * 2)) / 2;
+    y = screen_area->y + (screen_area->height -
+                          (h + ob_rr_theme->fbwidth * 2)) / 2;
+
+    if (!p->mapped) {
+        /* position the background but don't draw it*/
+        XMoveResizeWindow(ob_display, p->bg, x, y, w, h);
+
+        /* set up the hilite texture for the background */
+        p->a_bg->texture[0].data.rgba.width = w;
+        p->a_bg->texture[0].data.rgba.height = h;
+        p->hilite_rgba = g_new(RrPixel32, w * h);
+        p->a_bg->texture[0].data.rgba.data = p->hilite_rgba;
+
+        /* position the text, but don't draw it */
+        XMoveResizeWindow(ob_display, p->text, textx, texty, textw, texth);
+        p->a_text->surface.parentx = textx;
+        p->a_text->surface.parenty = texty;
+    }
+
+    /* find the focused target */
+    for (i = 0, it = p->targets; it; ++i, it = g_list_next(it)) {
+        const ObFocusCyclePopupTarget *target = it->data;
+        const gint row = i / icons_per_row; /* starting from 0 */
+        const gint col = i % icons_per_row; /* starting from 0 */
+
+        if (target->client == c) {
+            /* save the target */
+            newtarget = target;
+            newtargetx = l + (col * ICON_SIZE);
+            newtargety = t + (row * ICON_SIZE);
+
+            if (!p->mapped)
+                break; /* if we're not dimensioning, then we're done */
+        }
+    }
+
+    g_assert(newtarget != NULL);
+
+    /* create the hilite under the target icon */
+    {
+        RrPixel32 color = 0;
+        gint i, j;
+
+        memset(p->hilite_rgba, color, w * h * sizeof(RrPixel32));
+
+        for (i = 0; i < ICON_SIZE; ++i)
+            for (j = 0; j < ICON_SIZE; ++j) {
+                guchar a;
+
+                if (i < ICON_HILITE_WIDTH ||
+                    i >= ICON_SIZE-ICON_HILITE_WIDTH ||
+                    j < ICON_HILITE_WIDTH ||
+                    j >= ICON_SIZE-ICON_HILITE_WIDTH)
+                {
+                    /* the border of the target */
+                    a = 0x88;
+                }
+                else {
+                    /* the background of the target */
+                    a = 0x33;
+                }
+
+                p->hilite_rgba[(i+newtargety) * w + (j+newtargetx)] =
+                    color + (a << RrDefaultAlphaOffset);
+            }
+    }
+
+    /* * * draw everything * * */
+
+    /* draw the background */
+    RrPaint(p->a_bg, p->bg, w, h);
+
+    /* draw the icons */
+    for (i = 0, it = p->targets; it; ++i, it = g_list_next(it)) {
+        const ObFocusCyclePopupTarget *target = it->data;
+
+        /* have to redraw the targetted icon and last targetted icon,
+           they can pick up the hilite changes in the backgroud */
+        if (!p->mapped || newtarget == target || p->last_target == target) {
+            const ObClientIcon *icon;
+            const gint row = i / icons_per_row; /* starting from 0 */
+            const gint col = i % icons_per_row; /* starting from 0 */
+            gint iconx, icony;
+
+            /* find the dimensions of the icon inside it */
+            iconx = l + (col * ICON_SIZE) + ICON_HILITE_WIDTH +
+                ob_rr_theme->paddingx;
+            icony = t + (row * ICON_SIZE) + ICON_HILITE_WIDTH +
+                ob_rr_theme->paddingy;
+
+            /* move the icon */
+            XMoveResizeWindow(ob_display, target->win,
+                              iconx, icony, iconw, iconh);
+
+            /* get the icon from the client */
+            icon = client_icon(target->client, iconw, iconh);
+            p->a_icon->texture[0].data.rgba.width = icon->width;
+            p->a_icon->texture[0].data.rgba.height = icon->height;
+            p->a_icon->texture[0].data.rgba.data = icon->data;
+
+            /* draw the icon */
+            p->a_icon->surface.parentx = iconx;
+            p->a_icon->surface.parenty = icony;
+            RrPaint(p->a_icon, target->win, iconw, iconh);
+        }
+    }
+
+    /* draw the text */
+    p->a_text->texture[0].data.text.string = newtarget->text;
+    p->a_text->surface.parentx = textx;
+    p->a_text->surface.parenty = texty;
+    RrPaint(p->a_text, p->text, textw, texth);
+
+    p->last_target = newtarget;
+}
+
+void focus_cycle_popup_show(ObClient *c,
+                            gboolean all_desktops, gboolean dock_windows,
+                            gboolean desktop_windows)
+{
+    g_assert(c != NULL);
+
+    /* do this stuff only when the dialog is first showing */
+    if (!popup.mapped)
+        popup_setup(&popup, all_desktops, dock_windows, desktop_windows);
+    g_assert(popup.targets != NULL);
+
+    popup_render(&popup, c);
+
+    if (!popup.mapped) {
+        /* show the dialog */
+        XMapWindow(ob_display, popup.bg);
+        XFlush(ob_display);
+        popup.mapped = TRUE;
+    }
+}
+
+void focus_cycle_popup_hide()
+{
+    XUnmapWindow(ob_display, popup.bg);
+    XFlush(ob_display);
+
+    popup.mapped = FALSE;
+
+    while(popup.targets) {
+        ObFocusCyclePopupTarget *t = popup.targets->data;
+
+        g_free(t->text);
+        XDestroyWindow(ob_display, t->win);
+
+        popup.targets = g_list_delete_link(popup.targets, popup.targets);
+    }
+    popup.n_targets = 0;
+    popup.last_target = NULL;
+
+    g_free(popup.hilite_rgba);
+    popup.hilite_rgba = NULL;
+}
+
diff --git a/openbox/focus_cycle_popup.h b/openbox/focus_cycle_popup.h
new file mode 100644 (file)
index 0000000..695dfe5
--- /dev/null
@@ -0,0 +1,35 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+   focus_cycle.h for the Openbox window manager
+   Copyright (c) 2006        Mikael Magnusson
+   Copyright (c) 2003-2007   Dana Jansens
+
+   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.
+
+   See the COPYING file for a copy of the GNU General Public License.
+*/
+
+#ifndef __focus_cycle_popup_h
+#define __focus_cycle_popup_h
+
+struct _ObClient;
+
+#include <glib.h>
+
+void focus_cycle_popup_startup(gboolean reconfig);
+void focus_cycle_popup_shutdown(gboolean reconfig);
+
+void focus_cycle_popup_show(struct _ObClient *c,
+                            gboolean all_desktops, gboolean dock_windows,
+                            gboolean desktop_windows);
+void focus_cycle_popup_hide();
+
+#endif
index ecb07ada2b6ab200c27eed69ddaafc9541790e87..b357f8a35f759857a0eee0cfb124d6309a068ac8 100644 (file)
@@ -194,6 +194,14 @@ RrAppearance *RrAppearanceNew(const RrInstance *inst, gint numtex)
   return out;
 }
 
+void RrAppearanceAddTextures(RrAppearance *a, gint numtex)
+{
+    g_assert(a->textures == 0);
+
+    a->textures = numtex;
+    if (numtex) a->texture = g_new0(RrTexture, numtex);
+}
+
 RrAppearance *RrAppearanceCopy(RrAppearance *orig)
 {
     RrSurface *spo, *spc;
index ad638ae8b3705d9c3709fd78fa52c4f4f097c1f2..ac1deb4b0bf3ab8e32ce8e21b4a02c27ba2424dd 100644 (file)
@@ -230,6 +230,7 @@ GC       RrColorGC    (RrColor *c);
 RrAppearance *RrAppearanceNew  (const RrInstance *inst, gint numtex);
 RrAppearance *RrAppearanceCopy (RrAppearance *a);
 void          RrAppearanceFree (RrAppearance *a);
+void          RrAppearanceAddTextures(RrAppearance *a, gint numtex);
 
 RrFont *RrFontOpen          (const RrInstance *inst, const gchar *name, gint size,
                              RrFontWeight weight, RrFontSlant slant);
This page took 0.034398 seconds and 4 git commands to generate.