X-Git-Url: http://git.openbox.org/?p=mikachu%2Fopenbox.git;a=blobdiff_plain;f=openbox%2Fprompt.c;h=6084d798a063b05d510d648ec19b7393c93ada8d;hp=1c7e2261e25bc20f1ceae2e6dda97216f3751868;hb=b8960827b76ad499170e8b5b9ae8bf202188f0b0;hpb=972e1fc5a32e7d798fb3023012e73af20b5b03c7 diff --git a/openbox/prompt.c b/openbox/prompt.c index 1c7e226..6084d79 100644 --- a/openbox/prompt.c +++ b/openbox/prompt.c @@ -21,56 +21,91 @@ #include "screen.h" #include "openbox.h" #include "client.h" +#include "group.h" #include "prop.h" #include "modkeys.h" #include "event.h" #include "gettext.h" static GList *prompt_list = NULL; +static GList *prompt_msg_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; +static RrAppearance *prompt_a_pfocus; /* 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); void prompt_startup(gboolean reconfig) { - RrColor *c_button, *c_focus, *c_press; + RrColor *c_button, *c_focus, *c_press, *c_pfocus; + + /* note: this is not a copy, don't free it */ + prompt_a_bg = ob_rr_theme->osd_hilite_bg; prompt_a_button = RrAppearanceCopy(ob_rr_theme->a_focused_unpressed_close); prompt_a_focus = RrAppearanceCopy(ob_rr_theme->a_hover_focused_close); prompt_a_press = RrAppearanceCopy(ob_rr_theme->a_focused_pressed_close); + prompt_a_pfocus = RrAppearanceCopy(ob_rr_theme->a_focused_pressed_close); c_button = prompt_a_button->texture[0].data.mask.color; - c_focus = prompt_a_button->texture[0].data.mask.color; - c_press = prompt_a_button->texture[0].data.mask.color; + c_focus = prompt_a_focus->texture[0].data.mask.color; + c_press = prompt_a_press->texture[0].data.mask.color; + c_pfocus = prompt_a_press->texture[0].data.mask.color; RrAppearanceRemoveTextures(prompt_a_button); RrAppearanceRemoveTextures(prompt_a_focus); RrAppearanceRemoveTextures(prompt_a_press); + RrAppearanceRemoveTextures(prompt_a_pfocus); + /* texture[0] is the text and texture[1-4] (for prompt_a_focus and + prompt_a_pfocus) is lineart to show where keyboard focus is */ RrAppearanceAddTextures(prompt_a_button, 1); - RrAppearanceAddTextures(prompt_a_focus, 1); + RrAppearanceAddTextures(prompt_a_focus, 5); RrAppearanceAddTextures(prompt_a_press, 1); + RrAppearanceAddTextures(prompt_a_pfocus, 5); /* totally cheating here.. */ prompt_a_button->texture[0] = ob_rr_theme->osd_hilite_label->texture[0]; prompt_a_focus->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_pfocus->texture[0] = ob_rr_theme->osd_hilite_label->texture[0]; prompt_a_button->texture[0].data.text.justify = RR_JUSTIFY_CENTER; prompt_a_focus->texture[0].data.text.justify = RR_JUSTIFY_CENTER; prompt_a_press->texture[0].data.text.justify = RR_JUSTIFY_CENTER; + prompt_a_pfocus->texture[0].data.text.justify = RR_JUSTIFY_CENTER; prompt_a_button->texture[0].data.text.color = c_button; prompt_a_focus->texture[0].data.text.color = c_focus; prompt_a_press->texture[0].data.text.color = c_press; + prompt_a_pfocus->texture[0].data.text.color = c_press; + + prompt_a_focus->texture[1].data.lineart.color = c_focus; + prompt_a_focus->texture[2].data.lineart.color = c_focus; + prompt_a_focus->texture[3].data.lineart.color = c_focus; + prompt_a_focus->texture[4].data.lineart.color = c_focus; + + prompt_a_pfocus->texture[1].data.lineart.color = c_press; + prompt_a_pfocus->texture[2].data.lineart.color = c_press; + prompt_a_pfocus->texture[3].data.lineart.color = c_press; + prompt_a_pfocus->texture[4].data.lineart.color = c_press; prompt_a_msg = RrAppearanceCopy(ob_rr_theme->osd_hilite_label); prompt_a_msg->texture[0].data.text.flow = TRUE; @@ -87,9 +122,13 @@ void prompt_startup(gboolean reconfig) void prompt_shutdown(gboolean reconfig) { + while (prompt_msg_list) + prompt_cancel(prompt_msg_list->data); + RrAppearanceFree(prompt_a_button); RrAppearanceFree(prompt_a_focus); RrAppearanceFree(prompt_a_press); + RrAppearanceFree(prompt_a_pfocus); RrAppearanceFree(prompt_a_msg); } @@ -103,7 +142,6 @@ ObPrompt* prompt_new(const gchar *msg, gint i; attrib.override_redirect = FALSE; - attrib.border_pixel = RrColorPixel(ob_rr_theme->osd_border_color); self = g_new0(ObPrompt, 1); self->ref = 1; @@ -114,10 +152,10 @@ ObPrompt* prompt_new(const gchar *msg, self->super.type = Window_Prompt; self->super.window = XCreateWindow(ob_display, RootWindow(ob_display, ob_screen), - 0, 0, 1, 1, ob_rr_theme->obwidth, + 0, 0, 1, 1, 0, CopyFromParent, InputOutput, CopyFromParent, - CWOverrideRedirect | CWBorderPixel, + CWOverrideRedirect, &attrib); /* make it a dialog type window */ @@ -127,9 +165,6 @@ ObPrompt* prompt_new(const gchar *msg, /* listen for key presses on the window */ self->event_mask = KeyPressMask; - /* we make a copy of this appearance for each prompt */ - self->a_bg = RrAppearanceCopy(ob_rr_theme->osd_hilite_bg); - /* set up the text message widow */ self->msg.text = g_strdup(msg); self->msg.window = XCreateWindow(ob_display, self->super.window, @@ -187,6 +222,9 @@ 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); for (i = 0; i < self->n_buttons; ++i) { @@ -195,9 +233,6 @@ void prompt_unref(ObPrompt *self) } XDestroyWindow(ob_display, self->msg.window); - - RrAppearanceFree(self->a_bg); - XDestroyWindow(ob_display, self->super.window); g_free(self); } @@ -211,14 +246,7 @@ static void prompt_layout(ObPrompt *self) gint w, h; gint maxw; - const gint OUTSIDE_MARGIN = 4; - const gint MSG_BUTTON_SEPARATION = 4; - const gint BUTTON_SEPARATION = 4; - const gint BUTTON_VMARGIN = 4; - const gint BUTTON_HMARGIN = 12; - const gint MAX_WIDTH = 600; - - RrMargins(self->a_bg, &l, &t, &r, &b); + RrMargins(prompt_a_bg, &l, &t, &r, &b); l += OUTSIDE_MARGIN; t += OUTSIDE_MARGIN; r += OUTSIDE_MARGIN; @@ -238,6 +266,7 @@ static void prompt_layout(ObPrompt *self) 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; + prompt_a_pfocus->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; @@ -247,6 +276,10 @@ static void prompt_layout(ObPrompt *self) 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); + RrMinSize(prompt_a_pfocus, &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; @@ -280,11 +313,9 @@ static void prompt_layout(ObPrompt *self) } /* size and position the toplevel window */ - self->width = w + l + r; - self->height = h + t + b; + prompt_resize(self, w + l + r, h + t + b); - /* move and resize the actual windows */ - XResizeWindow(ob_display, self->super.window, self->width, self->height); + /* move and resize the internal windows */ XMoveResizeWindow(ob_display, self->msg.window, self->msg.x, self->msg.y, self->msg.width, self->msg.height); @@ -294,29 +325,110 @@ static void prompt_layout(ObPrompt *self) 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(ob_display, self->super.window, &hints); + + if (self->mapped) { + /* send a configure request like a normal client would */ + req.type = ConfigureRequest; + req.display = ob_display; + req.parent = RootWindow(ob_display, 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(ob_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->pressed) a = prompt_a_press; - else if (self->focus == e) a = prompt_a_focus; - else a = prompt_a_button; + if (e->pressed && self->focus == e) a = prompt_a_pfocus; + else if (self->focus == e) a = prompt_a_focus; + else if (e->pressed) a = prompt_a_press; + else a = prompt_a_button; - a->surface.parent = self->a_bg; + a->surface.parent = prompt_a_bg; a->surface.parentx = e->x; - a->surface.parentx = e->y; + a->surface.parenty = e->y; + + /* draw the keyfocus line */ + if (a == prompt_a_pfocus || a == prompt_a_focus) + 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 (a == prompt_a_pfocus || a == prompt_a_focus) + setup_button_focus_tex(e, a, FALSE); } static void render_all(ObPrompt *self) { gint i; - RrPaint(self->a_bg, self->super.window, self->width, self->height); + RrPaint(prompt_a_bg, self->super.window, self->width, self->height); - prompt_a_msg->surface.parent = self->a_bg; + prompt_a_msg->surface.parent = prompt_a_bg; prompt_a_msg->surface.parentx = self->msg.x; prompt_a_msg->surface.parenty = self->msg.y; @@ -328,9 +440,8 @@ static void render_all(ObPrompt *self) render_button(self, &self->button[i]); } -void prompt_show(ObPrompt *self, ObClient *parent) +void prompt_show(ObPrompt *self, ObClient *parent, gboolean modal) { - XSizeHints hints; gint i; if (self->mapped) { @@ -351,14 +462,33 @@ void prompt_show(ObPrompt *self, ObClient *parent) break; } - /* you can't resize the prompt */ - hints.flags = PMinSize | PMaxSize; - hints.min_width = hints.max_width = self->width; - hints.min_height = hints.max_height = self->height; - XSetWMNormalHints(ob_display, self->super.window, &hints); + 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 = RootWindow(ob_display, ob_screen); + } + else { + /* make it transient for the window directly */ + h.flags = 0; + p = parent->window; + } + + XSetWMHints(ob_display, self->super.window, &h); + PROP_SET32(self->super.window, wm_transient_for, window, p); - XSetTransientForHint(ob_display, self->super.window, - (parent ? parent->window : 0)); + states[0] = prop_atoms.net_wm_state_modal; + nstates = (modal ? 1 : 0); + PROP_SETA32(self->super.window, net_wm_state, atom, states, nstates); + } + else + PROP_ERASE(self->super.window, wm_transient_for); /* set up the dialog and render it */ prompt_layout(self); @@ -382,8 +512,6 @@ gboolean prompt_key_event(ObPrompt *self, XEvent *e) if (e->type != KeyPress) return FALSE; - g_print("key 0x%x 0x%x\n", e->xkey.keycode, ob_keycode(OB_KEY_TAB)); - shift_mask = modkeys_key_to_mask(OB_MODKEY_KEY_SHIFT); shift = !!(e->xkey.state & shift_mask); @@ -479,3 +607,21 @@ void prompt_cancel(ObPrompt *self) if (self->func) self->func(self, self->cancel_result, self->data); prompt_hide(self); } + +static void prompt_show_message_cb(ObPrompt *p, int res, gpointer data) +{ + prompt_msg_list = g_list_remove(prompt_msg_list, p); + prompt_unref(p); +} + +void prompt_show_message(const gchar *msg, const gchar *answer) +{ + ObPrompt *p; + ObPromptAnswer ans[] = { + { answer, 0 } + }; + + p = prompt_new(msg, ans, 1, 0, 0, prompt_show_message_cb, NULL); + prompt_msg_list = g_list_prepend(prompt_msg_list, p); + prompt_show(p, NULL, FALSE); +}