1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /** \file
3  * Desktop widget implementation.
4  */
5 /* Authors:
6  *   Jon A. Cruz <jon@joncruz.org>
7  *
8  * Copyright (C) 2010 Jon A. Cruz
9  *
10  * Released under GNU GPL v2+, read the file 'COPYING' for more information.
11  */
12 
13 #include <vector>
14 #include "widgets/desktop-widget.h"
15 
16 #include "uxmanager.h"
17 #include "desktop.h"
18 #include "ui/monitor.h"
19 #include "widgets/toolbox.h"
20 
21 class TrackItem
22 {
23 public:
TrackItem()24     TrackItem() :
25         destroyConn(),
26         boxes()
27     {}
28 
29     sigc::connection destroyConn;
30     std::vector<GtkWidget*> boxes;
31 };
32 
33 static std::vector<SPDesktop*> desktops;
34 static std::vector<SPDesktopWidget*> dtws;
35 static std::map<SPDesktop*, TrackItem> trackedBoxes;
36 
37 
38 namespace {
39 
desktopDestructHandler(SPDesktop * desktop)40 void desktopDestructHandler(SPDesktop *desktop)
41 {
42     std::map<SPDesktop*, TrackItem>::iterator it = trackedBoxes.find(desktop);
43     if (it != trackedBoxes.end())
44     {
45         trackedBoxes.erase(it);
46     }
47 }
48 
49 
50 // TODO unify this later:
getLayoutPrefPath(Inkscape::UI::View::View * view)51 static Glib::ustring getLayoutPrefPath( Inkscape::UI::View::View *view )
52 {
53     Glib::ustring prefPath;
54 
55     if (reinterpret_cast<SPDesktop*>(view)->is_focusMode()) {
56         prefPath = "/focus/";
57     } else if (reinterpret_cast<SPDesktop*>(view)->is_fullscreen()) {
58         prefPath = "/fullscreen/";
59     } else {
60         prefPath = "/window/";
61     }
62 
63     return prefPath;
64 }
65 
66 }
67 
68 namespace Inkscape {
69 namespace UI {
70 
71 UXManager* instance = nullptr;
72 
73 class UXManagerImpl : public UXManager
74 {
75 public:
76     UXManagerImpl();
77     ~UXManagerImpl() override;
78 
79     void addTrack( SPDesktopWidget* dtw ) override;
80     void delTrack( SPDesktopWidget* dtw ) override;
81 
82     void connectToDesktop( std::vector<GtkWidget *> const & toolboxes, SPDesktop *desktop ) override;
83 
84     gint getDefaultTask( SPDesktop *desktop ) override;
85     void setTask(SPDesktop* dt, gint val) override;
86 
87     bool isWidescreen() const override;
88 
89 private:
90     bool _widescreen;
91 };
92 
getInstance()93 UXManager* UXManager::getInstance()
94 {
95     if (!instance) {
96         instance = new UXManagerImpl();
97     }
98     return instance;
99 }
100 
101 
102 UXManager::UXManager()
103 = default;
104 
105 UXManager::~UXManager()
106 = default;
107 
UXManagerImpl()108 UXManagerImpl::UXManagerImpl() :
109     _widescreen(false)
110 {
111     // Figure out if we're on a widescreen display
112     Gdk::Rectangle monitor_geometry = Inkscape::UI::get_monitor_geometry_primary();
113     int const width  = monitor_geometry.get_width();
114     int const height = monitor_geometry.get_height();
115 
116     if (width && height) {
117         gdouble aspect = static_cast<gdouble>(width) / static_cast<gdouble>(height);
118         if (aspect > 1.65) {
119             _widescreen = true;
120         }
121     }
122 }
123 
124 UXManagerImpl::~UXManagerImpl()
125 = default;
126 
isWidescreen() const127 bool UXManagerImpl::isWidescreen() const
128 {
129     return _widescreen;
130 }
131 
getDefaultTask(SPDesktop * desktop)132 gint UXManagerImpl::getDefaultTask( SPDesktop *desktop )
133 {
134     gint taskNum = isWidescreen() ? 2 : 0;
135 
136     Glib::ustring prefPath = getLayoutPrefPath( desktop );
137     taskNum = Inkscape::Preferences::get()->getInt( prefPath + "task/taskset", taskNum );
138     taskNum = (taskNum < 0) ? 0 : (taskNum > 2) ? 2 : taskNum;
139 
140     return taskNum;
141 }
142 
setTask(SPDesktop * dt,gint val)143 void UXManagerImpl::setTask(SPDesktop* dt, gint val)
144 {
145     for (auto dtw : dtws) {
146         gboolean notDone = Inkscape::Preferences::get()->getBool("/options/workarounds/dynamicnotdone", false);
147 
148         if (dtw->desktop == dt) {
149             int taskNum = val;
150             switch (val) {
151                 default:
152                 case 0:
153                     dtw->setToolboxPosition("ToolToolbar", GTK_POS_LEFT);
154                     dtw->setToolboxPosition("CommandsToolbar", GTK_POS_TOP);
155                     if (notDone) {
156                         dtw->setToolboxPosition("AuxToolbar", GTK_POS_TOP);
157                     }
158                     dtw->setToolboxPosition("SnapToolbar", GTK_POS_RIGHT);
159                     taskNum = val; // in case it was out of range
160                     break;
161                 case 1:
162                     dtw->setToolboxPosition("ToolToolbar", GTK_POS_LEFT);
163                     dtw->setToolboxPosition("CommandsToolbar", GTK_POS_TOP);
164                     if (notDone) {
165                         dtw->setToolboxPosition("AuxToolbar", GTK_POS_TOP);
166                     }
167                     dtw->setToolboxPosition("SnapToolbar", GTK_POS_TOP);
168                     break;
169                 case 2:
170                     dtw->setToolboxPosition("ToolToolbar", GTK_POS_LEFT);
171                     dtw->setToolboxPosition("CommandsToolbar", GTK_POS_RIGHT);
172                     dtw->setToolboxPosition("SnapToolbar", GTK_POS_RIGHT);
173                     if (notDone) {
174                         dtw->setToolboxPosition("AuxToolbar", GTK_POS_RIGHT);
175                     }
176             }
177             Glib::ustring prefPath = getLayoutPrefPath( dtw->desktop );
178             Inkscape::Preferences::get()->setInt( prefPath + "task/taskset", taskNum );
179         }
180     }
181 }
182 
183 
addTrack(SPDesktopWidget * dtw)184 void UXManagerImpl::addTrack( SPDesktopWidget* dtw )
185 {
186     if (std::find(dtws.begin(), dtws.end(), dtw) == dtws.end()) {
187         dtws.push_back(dtw);
188     }
189 }
190 
delTrack(SPDesktopWidget * dtw)191 void UXManagerImpl::delTrack( SPDesktopWidget* dtw )
192 {
193     std::vector<SPDesktopWidget*>::iterator iter = std::find(dtws.begin(), dtws.end(), dtw);
194     if (iter != dtws.end()) {
195         dtws.erase(iter);
196     }
197 }
198 
connectToDesktop(std::vector<GtkWidget * > const & toolboxes,SPDesktop * desktop)199 void UXManagerImpl::connectToDesktop( std::vector<GtkWidget *> const & toolboxes, SPDesktop *desktop )
200 {
201     if (!desktop)
202     {
203         return;
204     }
205     TrackItem &tracker = trackedBoxes[desktop];
206     std::vector<GtkWidget*>& tracked = tracker.boxes;
207     tracker.destroyConn = desktop->connectDestroy(&desktopDestructHandler);
208 
209     for (auto toolbox : toolboxes) {
210         ToolboxFactory::setToolboxDesktop( toolbox, desktop );
211         if (find(tracked.begin(), tracked.end(), toolbox) == tracked.end()) {
212             tracked.push_back(toolbox);
213         }
214     }
215 
216     if (std::find(desktops.begin(), desktops.end(), desktop) == desktops.end()) {
217         desktops.push_back(desktop);
218     }
219 
220     gint taskNum = getDefaultTask( desktop );
221 
222     // note: this will change once more options are in the task set support:
223     Inkscape::UI::UXManager::getInstance()->setTask( desktop, taskNum );
224 }
225 
226 
227 } // namespace UI
228 } // namespace Inkscape
229 
230 /*
231   Local Variables:
232   mode:c++
233   c-file-style:"stroustrup"
234   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
235   indent-tabs-mode:nil
236   fill-column:99
237   End:
238 */
239 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
240