you can create dialog windows called "prompts" which have a message and some buttons! they don't do anything interesting yet.

This commit is contained in:
Dana Jansens 2008-02-06 21:35:55 -05:00
parent a0a9b0334b
commit a01ece1353
11 changed files with 395 additions and 7 deletions

View file

@ -256,6 +256,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/resist.c \

View file

@ -29,6 +29,7 @@
#include "frame.h"
#include "grab.h"
#include "menu.h"
#include "prompt.h"
#include "menuframe.h"
#include "keyboard.h"
#include "mouse.h"
@ -466,6 +467,7 @@ static void event_process(const XEvent *ec, gpointer data)
ObDockApp *dockapp = NULL;
ObWindow *obwin = NULL;
ObMenuFrame *menu = NULL;
ObPrompt *prompt = NULL;
/* make a copy we can mangle */
ee = *ec;
@ -488,6 +490,9 @@ static void event_process(const XEvent *ec, gpointer data)
case OB_WINDOW_CLASS_INTERNAL:
/* we don't do anything with events directly on these windows */
break;
case OB_WINDOW_CLASS_PROMPT:
prompt = WINDOW_AS_PROMPT(obwin);
break;
}
}
else

View file

@ -41,6 +41,7 @@
#include "group.h"
#include "config.h"
#include "ping.h"
#include "prompt.h"
#include "gettext.h"
#include "render/render.h"
#include "render/theme.h"
@ -293,6 +294,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);
@ -349,6 +351,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);

283
openbox/prompt.c Normal file
View file

@ -0,0 +1,283 @@
/* -*- 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 "obt/display.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 = OB_WINDOW_CLASS_PROMPT;
self->super.window = XCreateWindow(obt_display, obt_root(ob_screen),
0, 0, 1, 1, 0,
CopyFromParent, InputOutput,
CopyFromParent,
CWOverrideRedirect, &attrib);
window_add(&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(obt_display, self->super.window,
0, 0, 1, 1, 0,
CopyFromParent, InputOutput,
CopyFromParent, 0, NULL);
XMapWindow(obt_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(obt_display, self->super.window,
0, 0, 1, 1, 0,
CopyFromParent, InputOutput,
CopyFromParent, 0, NULL);
XMapWindow(obt_display, self->button[i].window);
window_add(&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) {
window_remove(self->button[i].window);
XDestroyWindow(obt_display, self->button[i].window);
}
XDestroyWindow(obt_display, self->msg.window);
RrAppearanceFree(self->a_bg);
window_remove(self->super.window);
XDestroyWindow(obt_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(obt_display, self->super.window,
self->x, self->y, self->width, self->height);
XMoveResizeWindow(obt_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(obt_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(obt_display, self->super.window);
self->mapped = TRUE;
}
void prompt_hide(ObPrompt *self)
{
XUnmapWindow(obt_display, self->super.window);
self->mapped = FALSE;
}

68
openbox/prompt.h Normal file
View file

@ -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
{
ObInternalWindow 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

View file

@ -23,6 +23,7 @@
#include "client.h"
#include "frame.h"
#include "openbox.h"
#include "prompt.h"
#include "debug.h"
#include "grab.h"
@ -57,6 +58,8 @@ Window window_top(ObWindow *self)
return WINDOW_AS_CLIENT(self)->frame->window;
case OB_WINDOW_CLASS_INTERNAL:
return WINDOW_AS_INTERNAL(self)->window;
case OB_WINDOW_CLASS_PROMPT:
return WINDOW_AS_PROMPT(self)->super.window;
}
g_assert_not_reached();
return None;
@ -71,6 +74,7 @@ ObStackingLayer window_layer(ObWindow *self)
return ((ObClient*)self)->layer;
case OB_WINDOW_CLASS_MENUFRAME:
case OB_WINDOW_CLASS_INTERNAL:
case OB_WINDOW_CLASS_PROMPT:
return OB_STACKING_LAYER_INTERNAL;
}
g_assert_not_reached();

View file

@ -31,7 +31,8 @@ typedef enum {
OB_WINDOW_CLASS_MENUFRAME,
OB_WINDOW_CLASS_DOCK,
OB_WINDOW_CLASS_CLIENT,
OB_WINDOW_CLASS_INTERNAL
OB_WINDOW_CLASS_INTERNAL,
OB_WINDOW_CLASS_PROMPT
} ObWindowClass;
/* In order to be an ObWindow, you need to make this struct the top of your
@ -48,21 +49,26 @@ struct _ObWindow {
(((ObWindow*)win)->type == OB_WINDOW_CLASS_CLIENT)
#define WINDOW_IS_INTERNAL(win) \
(((ObWindow*)win)->type == OB_WINDOW_CLASS_INTERNAL)
#define WINDOW_IS_PROMPT(win) \
(((ObWindow*)win)->type == OB_WINDOW_CLASS_PROMPT)
struct _ObMenu;
struct _ObDock;
struct _ObDockApp;
struct _ObClient;
struct _ObPrompt;
#define WINDOW_AS_MENUFRAME(win) ((struct _ObMenuFrame*)win)
#define WINDOW_AS_DOCK(win) ((struct _ObDock*)win)
#define WINDOW_AS_CLIENT(win) ((struct _ObClient*)win)
#define WINDOW_AS_INTERNAL(win) ((struct _ObInternalWindow*)win)
#define WINDOW_AS_PROMPT(win) ((struct _ObPrompt*)win)
#define MENUFRAME_AS_WINDOW(menu) ((ObWindow*)menu)
#define DOCK_AS_WINDOW(dock) ((ObWindow*)dock)
#define CLIENT_AS_WINDOW(client) ((ObWindow*)client)
#define INTERNAL_AS_WINDOW(intern) ((ObWindow*)intern)
#define PROMPT_AS_WINDOW(prompt) ((ObWindow*)prompt)
void window_startup (gboolean reconfig);
void window_shutdown(gboolean reconfig);

View file

@ -15,3 +15,4 @@ openbox/screen.c
openbox/session.c
openbox/startupnotify.c
openbox/translate.c
openbox/prompt.c

View file

@ -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;
}

View file

@ -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;

View file

@ -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);