177a0340a7
I managed to keep backwards compatibility without really cluttering the code so here is the patch http://bugzilla.icculus.org/show_bug.cgi?id=4874 too. Please keep in mind that this is my first piece of code for openbox and that I'm not a die hard openbox user (yet), not to tell the patch was not exhaustively tested. Anyway I think it's pretty much in a good shape but any criticism will be welcome. Basically the patch add the following theme options for controlling buttons in osd prompts: %%%% colors % % for the text inside the button osd.button.unpressed.text.color osd.button.pressed.text.color osd.button.focused.text.color % % for the line art around the button % (if you don't wan't the box just make box.color = bg.color) osd.button.pressed.box.color osd.button.focused.box.color %%%% textures % osd.button.unpressed.bg osd.button.pressed.bg osd.button.focused.bg The buttons can be in three states: unpressed: neither clicked nor selected focused: selected but not clicked pressed: clicked (and of course selected) I discarded the previous distinction between press and pfocus as in fact it was only a formal distinction, in that both appearances mimicked each other in every sense. It think that it was just inherited from the way titlebar buttons are managed so I decided to simplify it a bit. All the options default in a way that preserves backwards compatibility: osd.button.unpressed.text.color -> osd.active.label.text.color osd.button.pressed.text.color -> osd.active.label.text.color osd.button.focused.text.color -> osd.active.label.text.color osd.button.pressed.box.color -> window.active.button.pressed.image.color osd.button.focused.box.color -> window.active.button.hover.image.color osd.button.unpressed.bg -> window.active.button.unpressed.bg osd.button.pressed.bg -> window.active.button.pressed.bg osd.button.focused.bg -> window.active.button.hover.bg Notice that a good deal of locs where added to theme.c but in compensation prompt.c is pretty much simpler now because the appearances and textures are created while loading the theme.
603 lines
18 KiB
C
603 lines
18 KiB
C
/* -*- 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 "client.h"
|
|
#include "group.h"
|
|
#include "event.h"
|
|
#include "obt/display.h"
|
|
#include "obt/keyboard.h"
|
|
#include "obt/prop.h"
|
|
#include "gettext.h"
|
|
|
|
static GList *prompt_list = NULL;
|
|
|
|
/* we construct these */
|
|
static RrAppearance *prompt_a_bg;
|
|
static RrAppearance *prompt_a_button;
|
|
static RrAppearance *prompt_a_focus;
|
|
static RrAppearance *prompt_a_press;
|
|
/* we change the max width which would screw with others */
|
|
static RrAppearance *prompt_a_msg;
|
|
|
|
/* sizing stuff */
|
|
#define OUTSIDE_MARGIN 4
|
|
#define MSG_BUTTON_SEPARATION 4
|
|
#define BUTTON_SEPARATION 4
|
|
#define BUTTON_VMARGIN 4
|
|
#define BUTTON_HMARGIN 12
|
|
#define MAX_WIDTH 400
|
|
|
|
static void prompt_layout(ObPrompt *self);
|
|
static void render_all(ObPrompt *self);
|
|
static void render_button(ObPrompt *self, ObPromptElement *e);
|
|
static void prompt_resize(ObPrompt *self, gint w, gint h);
|
|
static void prompt_run_callback(ObPrompt *self, gint result);
|
|
|
|
void prompt_startup(gboolean reconfig)
|
|
{
|
|
/* note: this is not a copy, don't free it */
|
|
prompt_a_bg = ob_rr_theme->osd_bg;
|
|
|
|
prompt_a_button = RrAppearanceCopy(ob_rr_theme->osd_unpressed_button);
|
|
prompt_a_focus = RrAppearanceCopy(ob_rr_theme->osd_focused_button);
|
|
prompt_a_press = RrAppearanceCopy(ob_rr_theme->osd_pressed_button);
|
|
|
|
prompt_a_msg = RrAppearanceCopy(ob_rr_theme->osd_hilite_label);
|
|
prompt_a_msg->texture[0].data.text.flow = TRUE;
|
|
|
|
if (reconfig) {
|
|
GList *it;
|
|
for (it = prompt_list; it; it = g_list_next(it)) {
|
|
ObPrompt *p = it->data;
|
|
prompt_layout(p);
|
|
render_all(p);
|
|
}
|
|
}
|
|
}
|
|
|
|
void prompt_shutdown(gboolean reconfig)
|
|
{
|
|
GList *it;
|
|
|
|
if (!reconfig) {
|
|
for (it = prompt_list; it; it = g_list_next(it)) {
|
|
ObPrompt *p = it->data;
|
|
if (p->cleanup) p->cleanup(p, p->data);
|
|
}
|
|
|
|
g_assert(prompt_list == NULL);
|
|
}
|
|
|
|
RrAppearanceFree(prompt_a_button);
|
|
RrAppearanceFree(prompt_a_focus);
|
|
RrAppearanceFree(prompt_a_press);
|
|
RrAppearanceFree(prompt_a_msg);
|
|
}
|
|
|
|
ObPrompt* prompt_new(const gchar *msg, const gchar *title,
|
|
const ObPromptAnswer *answers, gint n_answers,
|
|
gint default_result, gint cancel_result,
|
|
ObPromptCallback func, ObPromptCleanup cleanup,
|
|
gpointer data)
|
|
{
|
|
ObPrompt *self;
|
|
XSetWindowAttributes attrib;
|
|
gint i;
|
|
|
|
attrib.override_redirect = FALSE;
|
|
|
|
self = g_slice_new0(ObPrompt);
|
|
self->ref = 1;
|
|
self->func = func;
|
|
self->cleanup = cleanup;
|
|
self->data = data;
|
|
self->default_result = default_result;
|
|
self->cancel_result = cancel_result;
|
|
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);
|
|
self->ic = obt_keyboard_context_new(self->super.window,
|
|
self->super.window);
|
|
|
|
/* make it a dialog type window */
|
|
OBT_PROP_SET32(self->super.window, NET_WM_WINDOW_TYPE, ATOM,
|
|
OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_DIALOG));
|
|
|
|
/* set the window's title */
|
|
if (title)
|
|
OBT_PROP_SETS(self->super.window, NET_WM_NAME, title);
|
|
|
|
/* listen for key presses on the window */
|
|
self->event_mask = KeyPressMask;
|
|
|
|
/* set up the text message widow */
|
|
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);
|
|
|
|
/* set up the buttons from the answers */
|
|
|
|
self->n_buttons = n_answers;
|
|
if (!self->n_buttons)
|
|
self->n_buttons = 1;
|
|
|
|
self->button = g_new0(ObPromptElement, self->n_buttons);
|
|
|
|
if (n_answers == 0) {
|
|
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].text);
|
|
self->button[i].result = answers[i].result;
|
|
}
|
|
}
|
|
|
|
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));
|
|
|
|
/* listen for button presses on the buttons */
|
|
XSelectInput(obt_display, self->button[i].window,
|
|
ButtonPressMask | ButtonReleaseMask | ButtonMotionMask);
|
|
}
|
|
|
|
prompt_list = g_list_prepend(prompt_list, self);
|
|
|
|
return self;
|
|
}
|
|
|
|
void prompt_ref(ObPrompt *self)
|
|
{
|
|
++self->ref;
|
|
}
|
|
|
|
void prompt_unref(ObPrompt *self)
|
|
{
|
|
if (self && --self->ref == 0) {
|
|
gint i;
|
|
|
|
if (self->mapped)
|
|
prompt_hide(self);
|
|
|
|
prompt_list = g_list_remove(prompt_list, self);
|
|
|
|
obt_keyboard_context_unref(self->ic);
|
|
|
|
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);
|
|
XDestroyWindow(obt_display, self->super.window);
|
|
g_slice_free(ObPrompt, self);
|
|
}
|
|
}
|
|
|
|
static void prompt_layout(ObPrompt *self)
|
|
{
|
|
gint l, r, t, b;
|
|
gint i;
|
|
gint allbuttonsw, allbuttonsh, buttonx;
|
|
gint w, h;
|
|
gint maxw;
|
|
|
|
RrMargins(prompt_a_bg, &l, &t, &r, &b);
|
|
l += OUTSIDE_MARGIN;
|
|
t += OUTSIDE_MARGIN;
|
|
r += OUTSIDE_MARGIN;
|
|
b += OUTSIDE_MARGIN;
|
|
|
|
{
|
|
const Rect *area = screen_physical_area_all_monitors();
|
|
maxw = MIN(MAX_WIDTH, area->width*4/5);
|
|
}
|
|
|
|
/* 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_focus->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_focus, &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);
|
|
|
|
self->button[i].width += BUTTON_HMARGIN * 2;
|
|
self->button[i].height += BUTTON_VMARGIN * 2;
|
|
|
|
allbuttonsw += self->button[i].width + (i > 0 ? BUTTON_SEPARATION : 0);
|
|
allbuttonsh = MAX(allbuttonsh, self->button[i].height);
|
|
}
|
|
|
|
self->msg_wbound = MAX(allbuttonsw, maxw);
|
|
|
|
/* measure the text message area */
|
|
prompt_a_msg->texture[0].data.text.string = self->msg.text;
|
|
prompt_a_msg->texture[0].data.text.maxwidth = self->msg_wbound;
|
|
RrMinSize(prompt_a_msg, &self->msg.width, &self->msg.height);
|
|
|
|
/* 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 on the right of the dialog */
|
|
buttonx = l + w;
|
|
for (i = self->n_buttons - 1; i >= 0; --i) {
|
|
self->button[i].x = buttonx - self->button[i].width;
|
|
buttonx -= self->button[i].width + BUTTON_SEPARATION;
|
|
self->button[i].y = t + h - allbuttonsh;
|
|
self->button[i].y += (allbuttonsh - self->button[i].height) / 2;
|
|
}
|
|
|
|
/* size and position the toplevel window */
|
|
prompt_resize(self, w + l + r, h + t + b);
|
|
|
|
/* move and resize the internal windows */
|
|
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 prompt_resize(ObPrompt *self, gint w, gint h)
|
|
{
|
|
XConfigureRequestEvent req;
|
|
XSizeHints hints;
|
|
|
|
self->width = w;
|
|
self->height = h;
|
|
|
|
/* the user can't resize the prompt */
|
|
hints.flags = PMinSize | PMaxSize;
|
|
hints.min_width = hints.max_width = w;
|
|
hints.min_height = hints.max_height = h;
|
|
XSetWMNormalHints(obt_display, self->super.window, &hints);
|
|
|
|
if (self->mapped) {
|
|
/* send a configure request like a normal client would */
|
|
req.type = ConfigureRequest;
|
|
req.display = obt_display;
|
|
req.parent = obt_root(ob_screen);
|
|
req.window = self->super.window;
|
|
req.width = w;
|
|
req.height = h;
|
|
req.value_mask = CWWidth | CWHeight;
|
|
XSendEvent(req.display, req.window, FALSE, StructureNotifyMask,
|
|
(XEvent*)&req);
|
|
}
|
|
else
|
|
XResizeWindow(obt_display, self->super.window, w, h);
|
|
}
|
|
|
|
static void setup_button_focus_tex(ObPromptElement *e, RrAppearance *a,
|
|
gboolean on)
|
|
{
|
|
gint i, l, r, t, b;
|
|
|
|
for (i = 1; i < 5; ++i)
|
|
a->texture[i].type = on ? RR_TEXTURE_LINE_ART : RR_TEXTURE_NONE;
|
|
|
|
if (!on) return;
|
|
|
|
RrMargins(a, &l, &t, &r, &b);
|
|
l += MIN(BUTTON_HMARGIN, BUTTON_VMARGIN) / 2;
|
|
r += MIN(BUTTON_HMARGIN, BUTTON_VMARGIN) / 2;
|
|
t += MIN(BUTTON_HMARGIN, BUTTON_VMARGIN) / 2;
|
|
b += MIN(BUTTON_HMARGIN, BUTTON_VMARGIN) / 2;
|
|
|
|
/* top line */
|
|
a->texture[1].data.lineart.x1 = l;
|
|
a->texture[1].data.lineart.x2 = e->width - r - 1;
|
|
a->texture[1].data.lineart.y1 = t;
|
|
a->texture[1].data.lineart.y2 = t;
|
|
|
|
/* bottom line */
|
|
a->texture[2].data.lineart.x1 = l;
|
|
a->texture[2].data.lineart.x2 = e->width - r - 1;
|
|
a->texture[2].data.lineart.y1 = e->height - b - 1;
|
|
a->texture[2].data.lineart.y2 = e->height - b - 1;
|
|
|
|
/* left line */
|
|
a->texture[3].data.lineart.x1 = l;
|
|
a->texture[3].data.lineart.x2 = l;
|
|
a->texture[3].data.lineart.y1 = t;
|
|
a->texture[3].data.lineart.y2 = e->height - b - 1;
|
|
|
|
/* right line */
|
|
a->texture[4].data.lineart.x1 = e->width - r - 1;
|
|
a->texture[4].data.lineart.x2 = e->width - r - 1;
|
|
a->texture[4].data.lineart.y1 = t;
|
|
a->texture[4].data.lineart.y2 = e->height - b - 1;
|
|
}
|
|
|
|
static void render_button(ObPrompt *self, ObPromptElement *e)
|
|
{
|
|
RrAppearance *a;
|
|
|
|
if (e->hover && e->pressed) a = prompt_a_press;
|
|
else if (self->focus == e) a = prompt_a_focus;
|
|
else a = prompt_a_button;
|
|
|
|
a->surface.parent = prompt_a_bg;
|
|
a->surface.parentx = e->x;
|
|
a->surface.parenty = e->y;
|
|
|
|
/* draw the keyfocus line */
|
|
if (self->focus == e)
|
|
setup_button_focus_tex(e, a, TRUE);
|
|
|
|
a->texture[0].data.text.string = e->text;
|
|
RrPaint(a, e->window, e->width, e->height);
|
|
|
|
/* turn off the keyfocus line so that it doesn't affect size calculations
|
|
*/
|
|
if (self->focus == e)
|
|
setup_button_focus_tex(e, a, FALSE);
|
|
}
|
|
|
|
static void render_all(ObPrompt *self)
|
|
{
|
|
gint i;
|
|
|
|
RrPaint(prompt_a_bg, self->super.window, self->width, self->height);
|
|
|
|
prompt_a_msg->surface.parent = prompt_a_bg;
|
|
prompt_a_msg->surface.parentx = self->msg.x;
|
|
prompt_a_msg->surface.parenty = self->msg.y;
|
|
|
|
prompt_a_msg->texture[0].data.text.string = self->msg.text;
|
|
prompt_a_msg->texture[0].data.text.maxwidth = self->msg_wbound;
|
|
RrPaint(prompt_a_msg, self->msg.window, self->msg.width, self->msg.height);
|
|
|
|
for (i = 0; i < self->n_buttons; ++i)
|
|
render_button(self, &self->button[i]);
|
|
}
|
|
|
|
void prompt_show(ObPrompt *self, ObClient *parent, gboolean modal)
|
|
{
|
|
gint i;
|
|
|
|
if (self->mapped) {
|
|
/* activate the prompt */
|
|
OBT_PROP_MSG(ob_screen, self->super.window, NET_ACTIVE_WINDOW,
|
|
1, /* from an application.. */
|
|
event_time(),
|
|
0,
|
|
0, 0);
|
|
return;
|
|
}
|
|
|
|
/* set the focused button (if not found then the first button is used) */
|
|
self->focus = &self->button[0];
|
|
for (i = 0; i < self->n_buttons; ++i)
|
|
if (self->button[i].result == self->default_result) {
|
|
self->focus = &self->button[i];
|
|
break;
|
|
}
|
|
|
|
if (parent) {
|
|
Atom states[1];
|
|
gint nstates;
|
|
Window p;
|
|
XWMHints h;
|
|
|
|
if (parent->group) {
|
|
/* make it transient for the window's group */
|
|
h.flags = WindowGroupHint;
|
|
h.window_group = parent->group->leader;
|
|
p = obt_root(ob_screen);
|
|
}
|
|
else {
|
|
/* make it transient for the window directly */
|
|
h.flags = 0;
|
|
p = parent->window;
|
|
}
|
|
|
|
XSetWMHints(obt_display, self->super.window, &h);
|
|
OBT_PROP_SET32(self->super.window, WM_TRANSIENT_FOR, WINDOW, p);
|
|
|
|
states[0] = OBT_PROP_ATOM(NET_WM_STATE_MODAL);
|
|
nstates = (modal ? 1 : 0);
|
|
OBT_PROP_SETA32(self->super.window, NET_WM_STATE, ATOM,
|
|
states, nstates);
|
|
}
|
|
else
|
|
OBT_PROP_ERASE(self->super.window, WM_TRANSIENT_FOR);
|
|
|
|
/* set up the dialog and render it */
|
|
prompt_layout(self);
|
|
render_all(self);
|
|
|
|
client_manage(self->super.window, self);
|
|
|
|
self->mapped = TRUE;
|
|
}
|
|
|
|
void prompt_hide(ObPrompt *self)
|
|
{
|
|
XUnmapWindow(obt_display, self->super.window);
|
|
self->mapped = FALSE;
|
|
}
|
|
|
|
gboolean prompt_key_event(ObPrompt *self, XEvent *e)
|
|
{
|
|
gboolean shift;
|
|
guint shift_mask, mods;
|
|
KeySym sym;
|
|
|
|
if (e->type != KeyPress) return FALSE;
|
|
|
|
shift_mask = obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_SHIFT);
|
|
mods = obt_keyboard_only_modmasks(e->xkey.state);
|
|
shift = !!(mods & shift_mask);
|
|
|
|
/* only accept shift */
|
|
if (mods != 0 && mods != shift_mask)
|
|
return FALSE;
|
|
|
|
sym = obt_keyboard_keypress_to_keysym(e);
|
|
|
|
if (sym == XK_Escape)
|
|
prompt_cancel(self);
|
|
else if (sym == XK_Return || sym == XK_KP_Enter || sym == XK_space)
|
|
prompt_run_callback(self, self->focus->result);
|
|
else if (sym == XK_Tab || sym == XK_Left || sym == XK_Right) {
|
|
gint i;
|
|
gboolean left;
|
|
ObPromptElement *oldfocus;
|
|
|
|
left = (sym == XK_Left) || ((sym == XK_Tab) && shift);
|
|
oldfocus = self->focus;
|
|
|
|
for (i = 0; i < self->n_buttons; ++i)
|
|
if (self->focus == &self->button[i]) break;
|
|
i += (left ? -1 : 1);
|
|
if (i < 0) i = self->n_buttons - 1;
|
|
else if (i >= self->n_buttons) i = 0;
|
|
self->focus = &self->button[i];
|
|
|
|
if (oldfocus != self->focus) render_button(self, oldfocus);
|
|
render_button(self, self->focus);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean prompt_mouse_event(ObPrompt *self, XEvent *e)
|
|
{
|
|
gint i;
|
|
ObPromptElement *but;
|
|
|
|
if (e->type != ButtonPress && e->type != ButtonRelease &&
|
|
e->type != MotionNotify) return FALSE;
|
|
|
|
/* find the button */
|
|
but = NULL;
|
|
for (i = 0; i < self->n_buttons; ++i)
|
|
if (self->button[i].window ==
|
|
(e->type == MotionNotify ? e->xmotion.window : e->xbutton.window))
|
|
{
|
|
but = &self->button[i];
|
|
break;
|
|
}
|
|
if (!but) return FALSE;
|
|
|
|
if (e->type == ButtonPress) {
|
|
ObPromptElement *oldfocus;
|
|
|
|
oldfocus = self->focus;
|
|
|
|
but->pressed = but->hover = TRUE;
|
|
self->focus = but;
|
|
|
|
if (oldfocus != but) render_button(self, oldfocus);
|
|
render_button(self, but);
|
|
}
|
|
else if (e->type == ButtonRelease) {
|
|
if (but->hover)
|
|
prompt_run_callback(self, but->result);
|
|
but->pressed = FALSE;
|
|
}
|
|
else if (e->type == MotionNotify) {
|
|
if (but->pressed) {
|
|
gboolean hover;
|
|
|
|
hover = (e->xmotion.x >= 0 && e->xmotion.y >= 0 &&
|
|
e->xmotion.x < but->width && e->xmotion.y < but->height);
|
|
|
|
if (hover != but->hover) {
|
|
but->hover = hover;
|
|
render_button(self, but);
|
|
}
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
void prompt_cancel(ObPrompt *self)
|
|
{
|
|
prompt_run_callback(self, self->cancel_result);
|
|
}
|
|
|
|
static gboolean prompt_show_message_cb(ObPrompt *p, int res, gpointer data)
|
|
{
|
|
return TRUE; /* call the cleanup func */
|
|
}
|
|
|
|
static void prompt_show_message_cleanup(ObPrompt *p, gpointer data)
|
|
{
|
|
prompt_unref(p);
|
|
}
|
|
|
|
ObPrompt* prompt_show_message(const gchar *msg, const gchar *title,
|
|
const gchar *answer)
|
|
{
|
|
ObPrompt *p;
|
|
ObPromptAnswer ans[] = {
|
|
{ answer, 0 }
|
|
};
|
|
|
|
p = prompt_new(msg, title, ans, 1, 0, 0,
|
|
prompt_show_message_cb, prompt_show_message_cleanup, NULL);
|
|
prompt_show(p, NULL, FALSE);
|
|
return p;
|
|
}
|
|
|
|
static void prompt_run_callback(ObPrompt *self, gint result)
|
|
{
|
|
prompt_ref(self);
|
|
if (self->func) {
|
|
gboolean clean = self->func(self, self->focus->result, self->data);
|
|
if (clean && self->cleanup)
|
|
self->cleanup(self, self->data);
|
|
}
|
|
prompt_hide(self);
|
|
prompt_unref(self);
|
|
}
|