]> icculus.org git repositories - mikachu/openbox.git/blob - otk/messagedialog.cc
add otk::MessageDialog
[mikachu/openbox.git] / otk / messagedialog.cc
1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2
3 #include "config.h"
4
5 #include "messagedialog.hh"
6 #include "assassin.hh"
7 #include "button.hh"
8 #include "label.hh"
9 #include "display.hh"
10 #include "property.hh"
11 #include "eventdispatcher.hh"
12 #include "timer.hh"
13
14 #include <algorithm>
15
16 namespace otk {
17
18 DialogButton MessageDialog::_default_result("", false);
19
20 class DialogButtonWidget : public Button {
21   MessageDialog *_dia;
22   const DialogButton &_res;
23 public:
24   DialogButtonWidget(Widget *parent, MessageDialog *dia,
25                      const DialogButton &b)
26     : Button(parent),
27       _dia(dia),
28       _res(b)
29   {
30     assert(dia);
31     setBevel(1);
32     setMaxSize(Size(0,0));
33     setText(b.label());
34     setHighlighted(b.isDefault());
35     show();
36   }
37
38   virtual void buttonPressHandler(const XButtonEvent &e) {
39     // limit to the left button
40     if (e.button == Button1)
41       Button::buttonPressHandler(e);
42   }
43   virtual void clickHandler(unsigned int) {
44     _dia->setResult(_res);
45     _dia->hide();
46   }
47 };
48
49 MessageDialog::MessageDialog(int screen, EventDispatcher *ed, ustring title,
50                              ustring caption)
51   : Widget(screen, ed, Widget::Vertical)
52 {
53   init(title, caption);
54 }
55
56 MessageDialog::MessageDialog(EventDispatcher *ed, ustring title,
57                              ustring caption)
58   : Widget(DefaultScreen(**display), ed, Widget::Vertical)
59 {
60   init(title, caption);
61 }
62
63 MessageDialog::MessageDialog(Widget *parent, ustring title, ustring caption)
64   : Widget(parent, Widget::Vertical)
65 {
66   init(title, caption);
67 }
68
69 void MessageDialog::init(const ustring &title, const ustring &caption)
70 {
71   _label = new Label(this);
72   _label->show();
73   _label->setHighlighted(true);
74   _button_holder = new Widget(this, Widget::Horizontal);
75   _button_holder->show();
76   _return = XKeysymToKeycode(**display, XStringToKeysym("Return"));
77   _escape = XKeysymToKeycode(**display, XStringToKeysym("Escape"));
78   _result = &_default_result;
79
80   setEventMask(eventMask() | KeyPressMask);
81   _label->setText(caption);
82   if (title.utf8())
83     otk::Property::set(window(), otk::Property::atoms.net_wm_name,
84                        otk::Property::utf8, title);
85   otk::Property::set(window(), otk::Property::atoms.wm_name,
86                      otk::Property::ascii, otk::ustring(title.c_str(), false));
87
88   // set WM Protocols on the window
89   Atom protocols[2];
90   protocols[0] = Property::atoms.wm_protocols;
91   protocols[1] = Property::atoms.wm_delete_window;
92   XSetWMProtocols(**display, window(), protocols, 2);
93 }
94
95 MessageDialog::~MessageDialog()
96 {
97   if (visible()) hide();
98   delete _button_holder;
99   delete _label;
100 }
101
102 const DialogButton& MessageDialog::run()
103 {
104   show();
105
106   while (visible()) {
107     dispatcher()->dispatchEvents();
108     if (visible())
109       Timer::dispatchTimers(); // fire pending events
110   }
111   return *_result;
112 }
113
114 void MessageDialog::show()
115 {
116   std::vector<DialogButton>::const_iterator it, end = _buttons.end();
117   for (it = _buttons.begin(); it != end; ++it)
118     _button_widgets.push_back(new DialogButtonWidget(_button_holder,
119                                                      this, *it));
120
121   XSizeHints size;
122   size.flags = PMinSize;
123   size.min_width = minSize().width();
124   size.min_height = minSize().height();
125   XSetWMNormalHints(**display, window(), &size);
126
127   Size dest = area().size();
128   if (dest.width() < 200 || dest.height() < 100) {
129     if (dest.width() < 200 && dest.height() < 100) dest = Size(200, 100);
130     else if (dest.width() < 200) dest = Size(200, dest.height());
131     else dest = Size(dest.width(), 100);
132     resize(dest);
133   }
134
135   Widget::show();
136 }
137
138 void MessageDialog::hide()
139 {
140   Widget::hide();
141   std::for_each(_button_widgets.begin(), _button_widgets.end(),
142                 PointerAssassin());
143 }
144
145 void MessageDialog::keyPressHandler(const XKeyEvent &e)
146 {
147   if (e.keycode == _return) {
148     std::vector<DialogButton>::const_iterator it, end = _buttons.end();
149     for (it = _buttons.begin(); it != end; ++it)
150       if (it->isDefault()) {
151         _result = &(*it);
152         break;
153       }
154     hide();
155   } else if (e.keycode == _escape) {
156     hide();
157   }
158 }
159
160 void MessageDialog::clientMessageHandler(const XClientMessageEvent &e)
161 {
162   EventHandler::clientMessageHandler(e);
163   if (e.message_type == Property::atoms.wm_protocols &&
164       static_cast<Atom>(e.data.l[0]) == Property::atoms.wm_delete_window)
165     hide();
166 }
167
168 }