summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDana Jansens <danakj@orodu.net>2008-02-06 21:35:55 -0500
committerDana Jansens <danakj@orodu.net>2008-02-14 14:24:07 -0500
commitc313b219a226c3b968ff312b96120eef0c527d91 (patch)
tree8bb87ba493631097a4672e8dd8109dd478064459
parentf9b59a49111b8db151af72aae334887105b4141b (diff)
you can create dialog windows called "prompts" which have a message and some buttons! they don't do anything interesting yet.
-rw-r--r--Makefile.am2
-rw-r--r--openbox/event.c5
-rw-r--r--openbox/openbox.c3
-rw-r--r--openbox/prompt.c286
-rw-r--r--openbox/prompt.h68
-rw-r--r--openbox/window.c4
-rw-r--r--openbox/window.h7
-rw-r--r--po/POTFILES.in1
-rw-r--r--render/font.c12
-rw-r--r--render/render.c11
-rw-r--r--render/render.h5
11 files changed, 397 insertions, 7 deletions
diff --git a/Makefile.am b/Makefile.am
index 9781ca84..df891ac0 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -250,6 +250,8 @@ openbox_openbox_SOURCES = \
openbox/ping.h \
openbox/place.c \
openbox/place.h \
+ openbox/prompt.c \
+ openbox/prompt.h \
openbox/popup.c \
openbox/popup.h \
openbox/prop.c \
diff --git a/openbox/event.c b/openbox/event.c
index 1b3c1c23..f41140eb 100644
--- a/openbox/event.c
+++ b/openbox/event.c
@@ -31,6 +31,7 @@
#include "frame.h"
#include "grab.h"
#include "menu.h"
+#include "prompt.h"
#include "menuframe.h"
#include "keyboard.h"
#include "modkeys.h"
@@ -459,6 +460,7 @@ static void event_process(const XEvent *ec, gpointer data)
ObWindow *obwin = NULL;
XEvent ee, *e;
ObEventData *ed = data;
+ ObPrompt *prompt = NULL;
/* make a copy we can mangle */
ee = *ec;
@@ -483,6 +485,9 @@ static void event_process(const XEvent *ec, gpointer data)
case Window_Internal:
/* we don't do anything with events directly on these windows */
break;
+ case Window_Prompt:
+ prompt = WINDOW_AS_PROMPT(obwin);
+ break;
}
}
diff --git a/openbox/openbox.c b/openbox/openbox.c
index 12106f6b..277294d0 100644
--- a/openbox/openbox.c
+++ b/openbox/openbox.c
@@ -46,6 +46,7 @@
#include "config.h"
#include "ping.h"
#include "mainloop.h"
+#include "prompt.h"
#include "gettext.h"
#include "parser/parse.h"
#include "render/render.h"
@@ -314,6 +315,7 @@ gint main(gint argc, gchar **argv)
grab_startup(reconfigure);
group_startup(reconfigure);
ping_startup(reconfigure);
+ prompt_startup(reconfigure);
client_startup(reconfigure);
dock_startup(reconfigure);
moveresize_startup(reconfigure);
@@ -373,6 +375,7 @@ gint main(gint argc, gchar **argv)
moveresize_shutdown(reconfigure);
dock_shutdown(reconfigure);
client_shutdown(reconfigure);
+ prompt_shutdown(reconfigure);
ping_shutdown(reconfigure);
group_shutdown(reconfigure);
grab_shutdown(reconfigure);
diff --git a/openbox/prompt.c b/openbox/prompt.c
new file mode 100644
index 00000000..38152411
--- /dev/null
+++ b/openbox/prompt.c
@@ -0,0 +1,286 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ prompt.c for the Openbox window manager
+ Copyright (c) 2008 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 "prompt.h"
+#include "openbox.h"
+#include "screen.h"
+#include "openbox.h"
+#include "gettext.h"
+
+static GList *prompt_list = NULL;
+
+/* we construct these */
+static RrAppearance *prompt_a_button;
+static RrAppearance *prompt_a_hover;
+static RrAppearance *prompt_a_press;
+
+#define msg_appearance(self) (ob_rr_theme->osd_hilite_label)
+
+void prompt_startup(gboolean reconfig)
+{
+ RrColor *c_button, *c_hover, *c_press;
+
+ prompt_a_button = RrAppearanceCopy(ob_rr_theme->a_focused_unpressed_close);
+ prompt_a_hover = RrAppearanceCopy(ob_rr_theme->a_hover_focused_close);
+ prompt_a_press = RrAppearanceCopy(ob_rr_theme->a_focused_pressed_close);
+
+ c_button = prompt_a_button->texture[0].data.mask.color;
+ c_hover = prompt_a_button->texture[0].data.mask.color;
+ c_press = prompt_a_button->texture[0].data.mask.color;
+
+ RrAppearanceRemoveTextures(prompt_a_button);
+ RrAppearanceRemoveTextures(prompt_a_hover);
+ RrAppearanceRemoveTextures(prompt_a_press);
+
+ RrAppearanceAddTextures(prompt_a_button, 1);
+ RrAppearanceAddTextures(prompt_a_hover, 1);
+ RrAppearanceAddTextures(prompt_a_press, 1);
+
+ /* totally cheating here.. */
+ prompt_a_button->texture[0] = ob_rr_theme->osd_hilite_label->texture[0];
+ prompt_a_hover->texture[0] = ob_rr_theme->osd_hilite_label->texture[0];
+ prompt_a_press->texture[0] = ob_rr_theme->osd_hilite_label->texture[0];
+
+ prompt_a_button->texture[0].data.text.color = c_button;
+ prompt_a_hover->texture[0].data.text.color = c_hover;
+ prompt_a_press->texture[0].data.text.color = c_press;
+}
+
+void prompt_shutdown(gboolean reconfig)
+{
+ RrAppearanceFree(prompt_a_button);
+ RrAppearanceFree(prompt_a_hover);
+ RrAppearanceFree(prompt_a_press);
+}
+
+ObPrompt* prompt_new(const gchar *msg, const gchar *const *answers)
+{
+ ObPrompt *self;
+ XSetWindowAttributes attrib;
+ guint i;
+ const gchar *const *c;
+
+ attrib.override_redirect = TRUE;
+
+ self = g_new0(ObPrompt, 1);
+ self->ref = 1;
+ self->super.type = Window_Prompt;
+ self->super.window = XCreateWindow(ob_display,
+ RootWindow(ob_display, ob_screen),
+ 0, 0, 1, 1, 0,
+ CopyFromParent, InputOutput,
+ CopyFromParent,
+ CWOverrideRedirect, &attrib);
+ g_hash_table_insert(window_map, &self->super.window,
+ PROMPT_AS_WINDOW(self));
+
+ self->a_bg = RrAppearanceCopy(ob_rr_theme->osd_hilite_bg);
+
+ self->msg.text = g_strdup(msg);
+ self->msg.window = XCreateWindow(ob_display, self->super.window,
+ 0, 0, 1, 1, 0,
+ CopyFromParent, InputOutput,
+ CopyFromParent, 0, NULL);
+ XMapWindow(ob_display, self->msg.window);
+
+ self->n_buttons = 0;
+ for (c = answers; *c != NULL; ++c)
+ ++self->n_buttons;
+
+ if (!self->n_buttons)
+ self->n_buttons = 1;
+
+ self->button = g_new(ObPromptElement, self->n_buttons);
+
+ if (!answers) {
+ g_assert(self->n_buttons == 1); /* should be set to this above.. */
+ self->button[0].text = g_strdup(_("OK"));
+ }
+ else {
+ g_assert(self->n_buttons > 0);
+ for (i = 0; i < self->n_buttons; ++i)
+ self->button[i].text = g_strdup(answers[i]);
+ }
+
+ for (i = 0; i < self->n_buttons; ++i) {
+ self->button[i].window = XCreateWindow(ob_display, self->super.window,
+ 0, 0, 1, 1, 0,
+ CopyFromParent, InputOutput,
+ CopyFromParent, 0, NULL);
+ XMapWindow(ob_display, self->button[i].window);
+ g_hash_table_insert(window_map, &self->button[i].window,
+ PROMPT_AS_WINDOW(self));
+ }
+
+ return self;
+}
+
+void prompt_ref(ObPrompt *self)
+{
+ ++self->ref;
+}
+
+void prompt_unref(ObPrompt *self)
+{
+ if (self && --self->ref == 0) {
+ guint i;
+
+ for (i = 0; i < self->n_buttons; ++i) {
+ g_hash_table_remove(window_map, &self->button[i].window);
+ XDestroyWindow(ob_display, self->button[i].window);
+ }
+
+ XDestroyWindow(ob_display, self->msg.window);
+
+ RrAppearanceFree(self->a_bg);
+
+ g_hash_table_remove(window_map, &self->super.window);
+ XDestroyWindow(ob_display, self->super.window);
+ g_free(self);
+ }
+}
+
+static void prompt_layout(ObPrompt *self, const Rect *area)
+{
+ RrAppearance *a_msg = msg_appearance(self);
+ gint l, r, t, b;
+ guint i;
+ gint allbuttonsw, allbuttonsh, buttonx;
+ gint w, h;
+
+ const gint OUTSIDE_MARGIN = 4;
+ const gint MSG_BUTTON_SEPARATION = 4;
+ const gint BUTTON_SEPARATION = 4;
+
+ RrMargins(self->a_bg, &l, &t, &r, &b);
+ l += OUTSIDE_MARGIN;
+ t += OUTSIDE_MARGIN;
+ r += OUTSIDE_MARGIN;
+ b += OUTSIDE_MARGIN;
+
+ /* find the button sizes and how much space we need for them */
+ allbuttonsw = allbuttonsh = 0;
+ for (i = 0; i < self->n_buttons; ++i) {
+ gint bw, bh;
+
+ prompt_a_button->texture[0].data.text.string = self->button[i].text;
+ prompt_a_hover->texture[0].data.text.string = self->button[i].text;
+ prompt_a_press->texture[0].data.text.string = self->button[i].text;
+ RrMinSize(prompt_a_button, &bw, &bh);
+ self->button[i].width = bw;
+ self->button[i].height = bh;
+ RrMinSize(prompt_a_hover, &bw, &bh);
+ self->button[i].width = MAX(self->button[i].width, bw);
+ self->button[i].height = MAX(self->button[i].height, bh);
+ RrMinSize(prompt_a_press, &bw, &bh);
+ self->button[i].width = MAX(self->button[i].width, bw);
+ self->button[i].height = MAX(self->button[i].height, bh);
+
+ allbuttonsw += self->button[i].width + (i > 0 ? BUTTON_SEPARATION : 0);
+ allbuttonsh = MAX(allbuttonsh, self->button[i].height);
+ }
+
+ self->msg_wbound = MAX(allbuttonsw, area->width*3/5);
+
+ /* measure the text message area */
+ a_msg->texture[0].data.text.string = self->msg.text;
+ a_msg->texture[0].data.text.maxwidth = self->msg_wbound;
+ RrMinSize(a_msg, &self->msg.width, &self->msg.height);
+ a_msg->texture[0].data.text.maxwidth = 0;
+
+ /* width and height inside the outer margins */
+ w = MAX(self->msg.width, allbuttonsw);
+ h = self->msg.height + MSG_BUTTON_SEPARATION + allbuttonsh;
+
+ /* position the text message */
+ self->msg.x = l + (w - self->msg.width) / 2;
+ self->msg.y = t;
+
+ /* position the button buttons */
+ buttonx = l + (w - allbuttonsw) / 2;
+ for (i = 0; i < self->n_buttons; ++i) {
+ self->button[i].x = buttonx;
+ buttonx += self->button[i].width + BUTTON_SEPARATION;
+ self->button[i].y = h - allbuttonsh;
+ self->button[i].y += (allbuttonsh - self->button[i].height) / 2;
+ }
+
+ /* size and position the toplevel window */
+ self->width = w + l + r;
+ self->height = h + t + b;
+ self->x = (area->width - self->width) / 2;
+ self->y = (area->height - self->height) / 2;
+
+ /* move and resize the actual windows */
+ XMoveResizeWindow(ob_display, self->super.window,
+ self->x, self->y, self->width, self->height);
+ XMoveResizeWindow(ob_display, self->msg.window,
+ self->msg.x, self->msg.y,
+ self->msg.width, self->msg.height);
+ for (i = 0; i < self->n_buttons; ++i)
+ XMoveResizeWindow(ob_display, self->button[i].window,
+ self->button[i].x, self->button[i].y,
+ self->button[i].width, self->button[i].height);
+}
+
+static void render_button(ObPrompt *self, ObPromptElement *e)
+{
+ prompt_a_button->surface.parent = self->a_bg;
+ prompt_a_button->surface.parentx = e->x;
+ prompt_a_button->surface.parentx = e->y;
+
+ prompt_a_button->texture[0].data.text.string = e->text;
+ RrPaint(prompt_a_button, e->window, e->width, e->height);
+}
+
+static void render_all(ObPrompt *self)
+{
+ guint i;
+
+ RrPaint(self->a_bg, self->super.window, self->width, self->height);
+
+ msg_appearance()->surface.parent = self->a_bg;
+ msg_appearance()->surface.parentx = self->msg.x;
+ msg_appearance()->surface.parentx = self->msg.y;
+
+ msg_appearance()->texture[0].data.text.string = self->msg.text;
+ msg_appearance()->texture[0].data.text.maxwidth = self->msg_wbound;
+ RrPaint(msg_appearance(), self->msg.window,
+ self->msg.width, self->msg.height);
+ msg_appearance()->texture[0].data.text.maxwidth = 0;
+
+ for (i = 0; i < self->n_buttons; ++i)
+ render_button(self, &self->button[i]);
+}
+
+void prompt_show(ObPrompt *self, const Rect *area)
+{
+ if (self->mapped) return;
+
+ prompt_layout(self, area);
+ render_all(self);
+ XMapWindow(ob_display, self->super.window);
+
+ self->mapped = TRUE;
+}
+
+void prompt_hide(ObPrompt *self)
+{
+ XUnmapWindow(ob_display, self->super.window);
+ self->mapped = FALSE;
+}
diff --git a/openbox/prompt.h b/openbox/prompt.h
new file mode 100644
index 00000000..6b27b8d8
--- /dev/null
+++ b/openbox/prompt.h
@@ -0,0 +1,68 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ prompt.h for the Openbox window manager
+ Copyright (c) 2008 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 ob__prompt_h
+#define ob__prompt_h
+
+typedef struct _ObPrompt ObPrompt;
+typedef struct _ObPromptElement ObPromptElement;
+
+#include "window.h"
+#include "geom.h"
+#include "render/render.h"
+#include <glib.h>
+
+struct _ObPromptElement {
+ gchar *text;
+ Window window;
+
+ gint x, y, width, height;
+};
+
+struct _ObPrompt
+{
+ InternalWindow super;
+ gint ref;
+
+ /* keep a copy of this because we re-render things that may need it
+ (i.e. the buttons) */
+ RrAppearance *a_bg;
+
+ gboolean mapped;
+ gint x, y, width, height;
+ gint msg_wbound;
+
+ ObPromptElement msg;
+
+ /* one for each answer */
+ ObPromptElement *button;
+ guint n_buttons;
+};
+
+void prompt_startup(gboolean reconfig);
+void prompt_shutdown(gboolean reconfig);
+
+ObPrompt* prompt_new(const gchar *msg, const gchar *const *answers);
+void prompt_ref(ObPrompt *self);
+void prompt_unref(ObPrompt *self);
+
+/*! Show the prompt. It will be centered within the given area rectangle */
+void prompt_show(ObPrompt *self, const Rect *area);
+void prompt_hide(ObPrompt *self);
+
+#endif
diff --git a/openbox/window.c b/openbox/window.c
index 3dd8f5ad..84afc4d8 100644
--- a/openbox/window.c
+++ b/openbox/window.c
@@ -22,6 +22,7 @@
#include "dock.h"
#include "client.h"
#include "frame.h"
+#include "prompt.h"
GHashTable *window_map;
@@ -58,6 +59,8 @@ Window window_top(ObWindow *self)
return ((ObClient*)self)->frame->window;
case Window_Internal:
return ((InternalWindow*)self)->window;
+ case Window_Prompt:
+ return ((ObPrompt*)self)->super.window;
}
g_assert_not_reached();
return None;
@@ -77,6 +80,7 @@ ObStackingLayer window_layer(ObWindow *self)
case Window_Client:
return ((ObClient*)self)->layer;
case Window_Internal:
+ case Window_Prompt:
return OB_STACKING_LAYER_INTERNAL;
}
g_assert_not_reached();
diff --git a/openbox/window.h b/openbox/window.h
index 7a905dea..76615c03 100644
--- a/openbox/window.h
+++ b/openbox/window.h
@@ -32,8 +32,9 @@ typedef enum {
Window_Dock,
Window_DockApp, /* used for events but not stacking */
Window_Client,
- Window_Internal /* used for stacking but not events (except to filter
+ Window_Internal,/* used for stacking but not events (except to filter
events on the root window) */
+ Window_Prompt,
} Window_InternalType;
struct _ObWindow
@@ -53,23 +54,27 @@ typedef struct InternalWindow {
#define WINDOW_IS_DOCKAPP(win) (((ObWindow*)win)->type == Window_DockApp)
#define WINDOW_IS_CLIENT(win) (((ObWindow*)win)->type == Window_Client)
#define WINDOW_IS_INTERNAL(win) (((ObWindow*)win)->type == Window_Internal)
+#define WINDOW_IS_PROMPT(win) (((ObWindow*)win)->type == Window_Prompt)
struct _ObMenu;
struct _ObDock;
struct _ObDockApp;
struct _ObClient;
+struct _ObPrompt;
#define WINDOW_AS_MENU(win) ((struct _ObMenuFrame*)win)
#define WINDOW_AS_DOCK(win) ((struct _ObDock*)win)
#define WINDOW_AS_DOCKAPP(win) ((struct _ObDockApp*)win)
#define WINDOW_AS_CLIENT(win) ((struct _ObClient*)win)
#define WINDOW_AS_INTERNAL(win) ((struct InternalWindow*)win)
+#define WINDOW_AS_PROMPT(win) ((struct _ObPrompt*)win)
#define MENU_AS_WINDOW(menu) ((ObWindow*)menu)
#define DOCK_AS_WINDOW(dock) ((ObWindow*)dock)
#define DOCKAPP_AS_WINDOW(dockapp) ((ObWindow*)dockapp)
#define CLIENT_AS_WINDOW(client) ((ObWindow*)client)
#define INTERNAL_AS_WINDOW(intern) ((ObWindow*)intern)
+#define PROMPT_AS_WINDOW(prompt) ((ObWindow*)prompt)
extern GHashTable *window_map;
diff --git a/po/POTFILES.in b/po/POTFILES.in
index f7918cec..294127c8 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -15,3 +15,4 @@ openbox/session.c
openbox/startupnotify.c
openbox/translate.c
openbox/xerror.c
+openbox/prompt.c
diff --git a/render/font.c b/render/font.c
index 369f262e..29d48215 100644
--- a/render/font.c
+++ b/render/font.c
@@ -109,6 +109,7 @@ RrFont *RrFontOpen(const RrInstance *inst, const gchar *name, gint size,
/* setup the layout */
pango_layout_set_font_description(out->layout, out->font_desc);
pango_layout_set_single_paragraph_mode(out->layout, TRUE);
+ pango_layout_set_wrap(out->layout, PANGO_WRAP_WORD_CHAR);
/* get the ascent and descent */
measure_font(inst, out);
@@ -139,12 +140,14 @@ void RrFontClose(RrFont *f)
}
static void font_measure_full(const RrFont *f, const gchar *str,
- gint *x, gint *y, gint shadow_x, gint shadow_y)
+ gint *x, gint *y, gint shadow_x, gint shadow_y,
+ gint maxwidth)
{
PangoRectangle rect;
pango_layout_set_text(f->layout, str, -1);
- pango_layout_set_width(f->layout, -1);
+ pango_layout_set_width(f->layout,
+ (maxwidth <= 0 ? -1 : maxwidth * PANGO_SCALE));
/* pango_layout_get_pixel_extents lies! this is the right way to get the
size of the text's area */
@@ -163,11 +166,12 @@ static void font_measure_full(const RrFont *f, const gchar *str,
}
RrSize *RrFontMeasureString(const RrFont *f, const gchar *str,
- gint shadow_x, gint shadow_y)
+ gint shadow_x, gint shadow_y, gint maxwidth)
{
RrSize *size;
size = g_new(RrSize, 1);
- font_measure_full(f, str, &size->width, &size->height, shadow_x, shadow_y);
+ font_measure_full(f, str, &size->width, &size->height, shadow_x, shadow_y,
+ maxwidth);
return size;
}
diff --git a/render/render.c b/render/render.c
index 4119dc7f..2147df01 100644
--- a/render/render.c
+++ b/render/render.c
@@ -178,6 +178,14 @@ RrAppearance *RrAppearanceNew(const RrInstance *inst, gint numtex)
return out;
}
+void RrAppearanceRemoveTextures(RrAppearance *a)
+{
+ gint i;
+
+ g_free(a->texture);
+ a->textures = 0;
+}
+
void RrAppearanceAddTextures(RrAppearance *a, gint numtex)
{
g_assert(a->textures == 0);
@@ -378,7 +386,8 @@ gint RrMinWidth(RrAppearance *a)
m = RrFontMeasureString(a->texture[i].data.text.font,
a->texture[i].data.text.string,
a->texture[i].data.text.shadow_offset_x,
- a->texture[i].data.text.shadow_offset_y);
+ a->texture[i].data.text.shadow_offset_y,
+ a->texture[i].data.text.maxwidth);
w = MAX(w, m->width);
g_free(m);
break;
diff --git a/render/render.h b/render/render.h
index 1f87c6e0..c812c316 100644
--- a/render/render.h
+++ b/render/render.h
@@ -141,6 +141,7 @@ struct _RrTextureText {
gboolean shortcut; /*!< Underline a character */
guint shortcut_pos; /*!< Position in bytes of the character to underline */
RrEllipsizeMode ellipsize;
+ gint maxwidth;
};
struct _RrPixmapMask {
@@ -244,6 +245,7 @@ GC RrColorGC (RrColor *c);
RrAppearance *RrAppearanceNew (const RrInstance *inst, gint numtex);
RrAppearance *RrAppearanceCopy (RrAppearance *a);
void RrAppearanceFree (RrAppearance *a);
+void RrAppearanceRemoveTextures(RrAppearance *a);
void RrAppearanceAddTextures(RrAppearance *a, gint numtex);
RrFont *RrFontOpen (const RrInstance *inst, const gchar *name,
@@ -251,7 +253,8 @@ RrFont *RrFontOpen (const RrInstance *inst, const gchar *name,
RrFont *RrFontOpenDefault (const RrInstance *inst);
void RrFontClose (RrFont *f);
RrSize *RrFontMeasureString (const RrFont *f, const gchar *str,
- gint shadow_offset_x, gint shadow_offset_y);
+ gint shadow_offset_x, gint shadow_offset_y,
+ gint maxwidth);
gint RrFontHeight (const RrFont *f, gint shadow_offset_y);
gint RrFontMaxCharWidth (const RrFont *f);