]> icculus.org git repositories - dana/openbox.git/blob - otk/messagedialog.cc
restart and catch errors appropriately
[dana/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 class DialogButtonWidget : public Button {
19   MessageDialog *_dia;
20 public:
21   DialogButtonWidget(Widget *parent, MessageDialog *dia,
22                      const DialogButton &b)
23     : Button(parent),
24       _dia(dia)
25   {
26     assert(dia);
27     setBevel(1);
28     setMaxSize(Size(0,0));
29     setText(b.label());
30     setHighlighted(b.isDefault());
31     show();
32   }
33
34   virtual void buttonPressHandler(const XButtonEvent &e) {
35     // limit to the left button
36     if (e.button == Button1)
37       Button::buttonPressHandler(e);
38   }
39   virtual void clickHandler(unsigned int) {
40     _dia->setResult(DialogButton(text(), isHighlighted()));
41     _dia->hide();
42   }
43 };
44
45 MessageDialog::MessageDialog(int screen, EventDispatcher *ed, ustring title,
46                              ustring caption)
47   : Widget(screen, ed, Widget::Vertical),
48     _result("", false)
49 {
50   init(title, caption);
51 }
52
53 MessageDialog::MessageDialog(EventDispatcher *ed, ustring title,
54                              ustring caption)
55   : Widget(DefaultScreen(**display), ed, Widget::Vertical),
56     _result("", false)
57 {
58   init(title, caption);
59 }
60
61 MessageDialog::MessageDialog(Widget *parent, ustring title, ustring caption)
62   : Widget(parent, Widget::Vertical),
63     _result("", false)
64 {
65   init(title, caption);
66 }
67
68 void MessageDialog::init(const ustring &title, const ustring &caption)
69 {
70   _label = new Label(this);
71   _label->show();
72   _label->setHighlighted(true);
73   _button_holder = new Widget(this, Widget::Horizontal);
74   _button_holder->show();
75   _return = XKeysymToKeycode(**display, XStringToKeysym("Return"));
76   _escape = XKeysymToKeycode(**display, XStringToKeysym("Escape"));
77
78   setEventMask(eventMask() | KeyPressMask);
79   _label->setText(caption);
80   if (title.utf8())
81     otk::Property::set(window(), otk::Property::atoms.net_wm_name,
82                        otk::Property::utf8, title);
83   otk::Property::set(window(), otk::Property::atoms.wm_name,
84                      otk::Property::ascii, otk::ustring(title.c_str(), false));
85
86   // set WM Protocols on the window
87   Atom protocols[2];
88   protocols[0] = Property::atoms.wm_protocols;
89   protocols[1] = Property::atoms.wm_delete_window;
90   XSetWMProtocols(**display, window(), protocols, 2);
91 }
92
93 MessageDialog::~MessageDialog()
94 {
95   if (visible()) hide();
96   delete _button_holder;
97   delete _label;
98 }
99
100 const DialogButton& MessageDialog::run()
101 {
102   if (!visible())
103     show();
104
105   while (visible()) {
106     dispatcher()->dispatchEvents();
107     if (visible())
108       Timer::dispatchTimers(); // fire pending events
109   }
110   return _result;
111 }
112
113 void MessageDialog::addButton(const DialogButton &b)
114 {
115   _button_widgets.push_back(new DialogButtonWidget(_button_holder,
116                                                    this, b));
117 }
118
119 void MessageDialog::focus()
120 {
121   if (visible())
122     XSetInputFocus(**display, window(), None, CurrentTime);
123 }
124
125 void MessageDialog::show()
126 {
127   Rect r;
128
129   if (parent())
130     r = parent()->area();
131   else
132     r = Rect(Point(0, 0), display->screenInfo(screen())->size());
133   
134   XSizeHints size;
135   size.flags = PMinSize | PPosition | PWinGravity;
136   size.min_width = minSize().width();
137   size.min_height = minSize().height();
138   size.win_gravity = CenterGravity;
139
140   Size dest = minSize();
141   if (dest.width() < 200 || dest.height() < 100) {
142     if (dest.width() < 200 && dest.height() < 100) dest = Size(200, 100);
143     else if (dest.width() < 200) dest = Size(200, dest.height());
144     else dest = Size(dest.width(), 100);
145     resize(dest);
146   }
147
148   // center it above its parent
149   move(Point(r.x() + (r.width() - dest.width()) / 2,
150              r.y() + (r.height() - dest.height()) / 2));
151   
152   XSetWMNormalHints(**display, window(), &size);
153   
154   Widget::show();
155 }
156
157 void MessageDialog::hide()
158 {
159   Widget::hide();
160   std::for_each(_button_widgets.begin(), _button_widgets.end(),
161                 PointerAssassin());
162 }
163
164 void MessageDialog::keyPressHandler(const XKeyEvent &e)
165 {
166   if (e.keycode == _return) {
167     std::vector<Button *>::const_iterator it, end = _button_widgets.end();
168     for (it = _button_widgets.begin(); it != end; ++it)
169       if ((*it)->isHighlighted()) {
170         _result = DialogButton((*it)->text(), true);
171         hide();
172         break;
173       }
174   } else if (e.keycode == _escape) {
175     hide();
176   }
177 }
178
179 void MessageDialog::clientMessageHandler(const XClientMessageEvent &e)
180 {
181   EventHandler::clientMessageHandler(e);
182   if (e.message_type == Property::atoms.wm_protocols &&
183       static_cast<Atom>(e.data.l[0]) == Property::atoms.wm_delete_window)
184     hide();
185 }
186
187 }