+
+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);
+}