238c6d9f7675702cc5d71ed7c36e024c86dd3cd3
1 /**
2 * \brief Base class for dialogs in Inkscape. This class provides certain
3 * common behaviors and styles wanted of all dialogs in the application.
4 *
5 * Author:
6 * Bryce W. Harrington <bryce@bryceharrington.org>
7 * buliabyak@gmail.com
8 *
9 * Copyright (C) 2004, 2005 Authors
10 *
11 * Released under GNU GPL. Read the file 'COPYING' for more information.
12 */
14 #ifdef HAVE_CONFIG_H
15 # include <config.h>
16 #endif
18 #include <typeinfo>
19 #include <gtkmm/stock.h>
20 #include <gtk/gtk.h>
22 #include "application/application.h"
23 #include "application/editor.h"
24 #include "inkscape.h"
25 #include "event-context.h"
26 #include "desktop.h"
27 #include "desktop-handles.h"
28 #include "dialog-manager.h"
29 #include "dialogs/dialog-events.h"
30 #include "shortcuts.h"
31 #include "prefs-utils.h"
32 #include "interface.h"
33 #include "verbs.h"
35 namespace Inkscape {
36 namespace UI {
37 namespace Dialog {
39 #ifndef WIN32
40 static gboolean
41 sp_retransientize_again (gpointer dlgPtr)
42 {
43 Dialog *dlg = (Dialog *)dlgPtr;
44 dlg->retransientize_suppress = false;
45 return FALSE; // so that it is only called once
46 }
47 #endif
49 static void
50 sp_retransientize (Inkscape::Application *inkscape, SPDesktop *desktop, gpointer dlgPtr)
51 {
52 Dialog *dlg = (Dialog *)dlgPtr;
53 dlg->onDesktopActivated (desktop);
54 }
56 static void
57 sp_dialog_shutdown (GtkObject *object, gpointer dlgPtr)
58 {
59 Dialog *dlg = (Dialog *)dlgPtr;
60 dlg->onShutdown();
61 }
63 void
64 Dialog::present()
65 {
66 Gtk::Dialog::present();
67 }
69 void
70 Dialog::save_geometry()
71 {
72 int y, x, w, h;
74 get_position(x, y);
75 get_size(w, h);
77 // g_print ("write %d %d %d %d\n", x, y, w, h);
79 if (x<0) x=0;
80 if (y<0) y=0;
82 prefs_set_int_attribute (_prefs_path, "x", x);
83 prefs_set_int_attribute (_prefs_path, "y", y);
84 prefs_set_int_attribute (_prefs_path, "w", w);
85 prefs_set_int_attribute (_prefs_path, "h", h);
86 }
88 void
89 Dialog::read_geometry()
90 {
91 _user_hidden = false;
93 int x = prefs_get_int_attribute (_prefs_path, "x", -1000);
94 int y = prefs_get_int_attribute (_prefs_path, "y", -1000);
95 int w = prefs_get_int_attribute (_prefs_path, "w", 0);
96 int h = prefs_get_int_attribute (_prefs_path, "h", 0);
98 // g_print ("read %d %d %d %d\n", x, y, w, h);
100 if (x<0) x=0;
101 if (y<0) y=0;
103 // If there are stored height and width values for the dialog,
104 // resize the window to match; otherwise we leave it at its default
105 if (w != 0 && h != 0) {
106 resize (w, h);
107 }
109 // If there are stored values for where the dialog should be
110 // located, then restore the dialog to that position.
111 if (x != -1000 && y != -1000) {
112 move(x, y);
113 } else {
114 // ...otherwise just put it in the middle of the screen
115 set_position(Gtk::WIN_POS_CENTER);
116 }
117 }
119 void hideCallback(GtkObject *object, gpointer dlgPtr)
120 {
121 Dialog* example;
122 if ((void*)dlgPtr == 0 || typeid(dlgPtr) != typeid(example))
123 return;
125 Dialog *dlg = (Dialog *)dlgPtr;
126 dlg->onHideF12();
127 }
129 void unhideCallback(GtkObject *object, gpointer dlgPtr)
130 {
131 Dialog* example;
132 if ((void*)dlgPtr == 0 || typeid(dlgPtr) != typeid(example))
133 return;
135 Dialog *dlg = (Dialog *)dlgPtr;
136 dlg->onShowF12();
137 }
139 //=====================================================================
141 /**
142 * UI::Dialog::Dialog is a base class for all dialogs in Inkscape. The
143 * purpose of this class is to provide a unified place for ensuring
144 * style and behavior. Specifically, this class provides functionality
145 * for saving and restoring the size and position of dialogs (through
146 * the user's preferences file).
147 *
148 * It also provides some general purpose signal handlers for things like
149 * showing and hiding all dialogs.
150 */
151 Dialog::Dialog(const char *prefs_path, int verb_num, const char *apply_label)
152 {
153 hide();
154 set_has_separator(false);
156 _prefs_path = prefs_path;
158 if (prefs_get_int_attribute ("dialogs", "showclose", 0) || apply_label) {
159 // TODO: make the order of buttons obey the global preference
160 if (apply_label) {
161 add_button(Glib::ustring(apply_label), Gtk::RESPONSE_APPLY);
162 set_default_response(Gtk::RESPONSE_APPLY);
163 }
164 add_button(Gtk::Stock::CLOSE, Gtk::RESPONSE_CLOSE);
165 }
167 GtkWidget *dlg = GTK_WIDGET(gobj());
169 if (verb_num)
170 {
171 gchar title[500];
172 sp_ui_dialog_title_string (Inkscape::Verb::get(verb_num), title);
173 set_title(title);
174 }
176 sp_transientize(dlg);
177 retransientize_suppress = false;
179 gtk_signal_connect( GTK_OBJECT (dlg), "event", GTK_SIGNAL_FUNC(sp_dialog_event_handler), dlg );
181 _hiddenF12 = false;
182 if (Inkscape::NSApplication::Application::getNewGui())
183 {
184 _desktop_activated_connection = Inkscape::NSApplication::Editor::connectDesktopActivated (sigc::mem_fun (*this, &Dialog::onDesktopActivated));
185 _dialogs_hidden_connection = Inkscape::NSApplication::Editor::connectDialogsHidden (sigc::mem_fun (*this, &Dialog::onHideF12));
186 _dialogs_unhidden_connection = Inkscape::NSApplication::Editor::connectDialogsUnhidden (sigc::mem_fun (*this, &Dialog::onShowF12));
187 _shutdown_connection = Inkscape::NSApplication::Editor::connectShutdown (sigc::mem_fun (*this, &Dialog::onShutdown));
188 }
189 else
190 {
191 g_signal_connect (G_OBJECT (INKSCAPE), "activate_desktop", G_CALLBACK (sp_retransientize), (void *)this);
192 g_signal_connect( G_OBJECT(INKSCAPE), "dialogs_hide", G_CALLBACK(hideCallback), (void *)this );
193 g_signal_connect( G_OBJECT(INKSCAPE), "dialogs_unhide", G_CALLBACK(unhideCallback), (void *)this );
194 g_signal_connect (G_OBJECT (INKSCAPE), "shut_down", G_CALLBACK (sp_dialog_shutdown), (void *)this);
195 }
197 g_signal_connect_after( gobj(), "key_press_event", (GCallback)windowKeyPress, NULL );
199 read_geometry();
200 present();
201 }
203 Dialog::Dialog(BaseObjectType *gobj)
204 : Gtk::Dialog(gobj)
205 {
206 }
208 Dialog::~Dialog()
209 {
210 if (Inkscape::NSApplication::Application::getNewGui())
211 {
212 _desktop_activated_connection.disconnect();
213 _dialogs_hidden_connection.disconnect();
214 _dialogs_unhidden_connection.disconnect();
215 _shutdown_connection.disconnect();
216 }
218 save_geometry();
219 }
222 bool Dialog::windowKeyPress( GtkWidget *widget, GdkEventKey *event )
223 {
224 unsigned int shortcut = 0;
225 shortcut = get_group0_keyval (event) |
226 ( event->state & GDK_SHIFT_MASK ?
227 SP_SHORTCUT_SHIFT_MASK : 0 ) |
228 ( event->state & GDK_CONTROL_MASK ?
229 SP_SHORTCUT_CONTROL_MASK : 0 ) |
230 ( event->state & GDK_MOD1_MASK ?
231 SP_SHORTCUT_ALT_MASK : 0 );
232 return sp_shortcut_invoke( shortcut, SP_ACTIVE_DESKTOP );
233 }
235 //---------------------------------------------------------------------
237 void
238 Dialog::on_response(int response_id)
239 {
240 switch (response_id) {
241 case Gtk::RESPONSE_APPLY: {
242 _apply();
243 break;
244 }
245 case Gtk::RESPONSE_CLOSE: {
246 _close();
247 break;
248 }
249 }
250 }
252 bool
253 Dialog::on_delete_event (GdkEventAny *event)
254 {
255 save_geometry();
256 _user_hidden = true;
258 return false;
259 }
261 void
262 Dialog::onHideF12()
263 {
264 _hiddenF12 = true;
265 save_geometry();
266 hide();
267 }
269 void
270 Dialog::onShowF12()
271 {
272 if (_user_hidden)
273 return;
275 if (_hiddenF12) {
276 show();
277 read_geometry();
278 }
280 _hiddenF12 = false;
281 }
283 void
284 Dialog::onShutdown()
285 {
286 save_geometry();
287 _user_hidden = true;
288 }
290 void
291 Dialog::onDesktopActivated (SPDesktop *desktop)
292 {
293 gint transient_policy = prefs_get_int_attribute_limited ( "options.transientpolicy", "value", 1, 0, 2);
295 if (!transient_policy)
296 return;
298 #ifndef WIN32
299 GtkWindow *dialog_win = GTK_WINDOW(gobj());
301 if (retransientize_suppress) {
302 /* if retransientizing of this dialog is still forbidden after
303 * previous call warning turned off because it was confusingly fired
304 * when loading many files from command line
305 */
307 // g_warning("Retranzientize aborted! You're switching windows too fast!");
308 return;
309 }
311 if (dialog_win)
312 {
313 retransientize_suppress = true; // disallow other attempts to retranzientize this dialog
315 desktop->setWindowTransient (dialog_win);
317 /*
318 * This enables "aggressive" transientization,
319 * i.e. dialogs always emerging on top when you switch documents. Note
320 * however that this breaks "click to raise" policy of a window
321 * manager because the switched-to document will be raised at once
322 * (so that its transients also could raise)
323 */
324 if (transient_policy == 2 && !_hiddenF12 && !_user_hidden) {
325 // without this, a transient window not always emerges on top
326 gtk_window_present (dialog_win);
327 }
328 }
330 // we're done, allow next retransientizing not sooner than after 120 msec
331 gtk_timeout_add (120, (GtkFunction) sp_retransientize_again, (gpointer) this);
332 #endif
333 }
336 Inkscape::Selection*
337 Dialog::_getSelection()
338 {
339 return SP_DT_SELECTION(SP_ACTIVE_DESKTOP);
340 }
342 void
343 Dialog::_apply()
344 {
345 g_warning("Apply button clicked for dialog [Dialog::_apply()]");
346 }
348 void
349 Dialog::_close()
350 {
351 GtkWidget *dlg = GTK_WIDGET(gobj());
353 /* this code sends a delete_event to the dialog,
354 * instead of just destroying it, so that the
355 * dialog can do some housekeeping, such as remember
356 * its position.
357 */
358 GdkEventAny event;
359 event.type = GDK_DELETE;
360 event.window = dlg->window;
361 event.send_event = TRUE;
362 g_object_ref (G_OBJECT (event.window));
363 gtk_main_do_event ((GdkEvent*)&event);
364 g_object_unref (G_OBJECT (event.window));
365 }
367 } // namespace Dialog
368 } // namespace UI
369 } // namespace Inkscape
371 /*
372 Local Variables:
373 mode:c++
374 c-file-style:"stroustrup"
375 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
376 indent-tabs-mode:nil
377 fill-column:99
378 End:
379 */
380 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :