1 #include "MainWindow.h"
2
3 #include <config-dev.h>
4 #include <config-features.h>
5 #include <config.h>
6
7 #include "control/Control.h"
8 #include "control/layer/LayerController.h"
9 #include "gui/GladeSearchpath.h"
10 #include "gui/scroll/ScrollHandling.h"
11 #include "toolbarMenubar/ToolMenuHandler.h"
12 #include "toolbarMenubar/model/ToolbarData.h"
13 #include "toolbarMenubar/model/ToolbarModel.h"
14 #include "widgets/SpinPageAdapter.h"
15 #include "widgets/XournalWidget.h"
16
17 #include "Layout.h"
18 #include "MainWindowToolbarMenu.h"
19 #include "ToolbarDefinitions.h"
20 #include "ToolitemDragDrop.h"
21 #include "XojMsgBox.h"
22 #include "XournalView.h"
23 #include "i18n.h"
24
25 #include <utility>
26
27 #include <gdk/gdk.h>
28
29 #include "gui/inputdevices/InputEvents.h"
30 #include "util/DeviceListHelper.h"
31
MainWindow(GladeSearchpath * gladeSearchPath,Control * control)32 MainWindow::MainWindow(GladeSearchpath* gladeSearchPath, Control* control):
33 GladeGui(gladeSearchPath, "main.glade", "mainWindow") {
34 this->control = control;
35 this->toolbarWidgets = new GtkWidget*[TOOLBAR_DEFINITIONS_LEN];
36 this->toolbarSelectMenu = new MainWindowToolbarMenu(this);
37
38 panedContainerWidget = GTK_WIDGET(get("panelMainContents"));
39 boxContainerWidget = GTK_WIDGET(get("mainContentContainer"));
40 mainContentWidget = GTK_WIDGET(get("boxContents"));
41 sidebarWidget = GTK_WIDGET(get("sidebar"));
42 g_object_ref(panedContainerWidget);
43 g_object_ref(boxContainerWidget);
44 g_object_ref(mainContentWidget);
45 g_object_ref(sidebarWidget);
46
47 loadMainCSS(gladeSearchPath, "xournalpp.css");
48
49 GtkOverlay* overlay = GTK_OVERLAY(get("mainOverlay"));
50 this->floatingToolbox = new FloatingToolbox(this, overlay);
51
52
53 for (int i = 0; i < TOOLBAR_DEFINITIONS_LEN; i++) {
54 GtkWidget* w = get(TOOLBAR_DEFINITIONS[i].guiName);
55 g_object_ref(w);
56 this->toolbarWidgets[i] = w;
57 }
58
59 initXournalWidget();
60
61 setSidebarVisible(control->getSettings()->isSidebarVisible());
62
63 // Window handler
64 g_signal_connect(this->window, "delete-event", G_CALLBACK(deleteEventCallback), this->control);
65 g_signal_connect(this->window, "window_state_event", G_CALLBACK(windowStateEventCallback), this);
66
67 g_signal_connect(get("buttonCloseSidebar"), "clicked", G_CALLBACK(buttonCloseSidebarClicked), this);
68
69
70 // "watch over" all events
71 g_signal_connect(this->window, "key-press-event", G_CALLBACK(onKeyPressCallback), this);
72
73 this->toolbar = new ToolMenuHandler(this->control, this, GTK_WINDOW(getWindow()));
74
75 auto file = gladeSearchPath->findFile("", "toolbar.ini");
76
77 ToolbarModel* tbModel = this->toolbar->getModel();
78
79 if (!tbModel->parse(file, true)) {
80
81 string msg = FS(_F("Could not parse general toolbar.ini file: {1}\n"
82 "No Toolbars will be available") %
83 file.u8string());
84 XojMsgBox::showErrorToUser(control->getGtkWindow(), msg);
85 }
86
87 file = Util::getConfigFile(TOOLBAR_CONFIG);
88 if (fs::exists(file)) {
89 if (!tbModel->parse(file, false)) {
90 string msg = FS(_F("Could not parse custom toolbar.ini file: {1}\n"
91 "Toolbars will not be available") %
92 file.u8string());
93 XojMsgBox::showErrorToUser(control->getGtkWindow(), msg);
94 }
95 }
96
97 createToolbarAndMenu();
98
99 setToolbarVisible(control->getSettings()->isToolbarVisible());
100
101 GtkWidget* menuViewSidebarVisible = get("menuViewSidebarVisible");
102 g_signal_connect(menuViewSidebarVisible, "toggled", G_CALLBACK(viewShowSidebar), this);
103
104 GtkWidget* menuViewToolbarsVisible = get("menuViewToolbarsVisible");
105 g_signal_connect(menuViewToolbarsVisible, "toggled", G_CALLBACK(viewShowToolbar), this);
106
107 updateScrollbarSidebarPosition();
108
109 gtk_window_set_default_size(GTK_WINDOW(this->window), control->getSettings()->getMainWndWidth(),
110 control->getSettings()->getMainWndHeight());
111
112 if (control->getSettings()->isMainWndMaximized()) {
113 gtk_window_maximize(GTK_WINDOW(this->window));
114 } else {
115 gtk_window_unmaximize(GTK_WINDOW(this->window));
116 }
117
118 getSpinPageNo()->addListener(this->control->getScrollHandler());
119
120
121 Util::execInUiThread([=]() {
122 // Execute after the window is visible, else the check won't work
123 initHideMenu();
124 });
125
126 // Drag and Drop
127 g_signal_connect(this->window, "drag-data-received", G_CALLBACK(dragDataRecived), this);
128
129 gtk_drag_dest_set(this->window, GTK_DEST_DEFAULT_ALL, nullptr, 0, GDK_ACTION_COPY);
130 gtk_drag_dest_add_uri_targets(this->window);
131 gtk_drag_dest_add_image_targets(this->window);
132 gtk_drag_dest_add_text_targets(this->window);
133
134 LayerCtrlListener::registerListener(control->getLayerController());
135 }
136
isKeyForClosure(GtkAccelKey * key,GClosure * closure,gpointer data)137 gboolean MainWindow::isKeyForClosure(GtkAccelKey* key, GClosure* closure, gpointer data) { return closure == data; }
138
invokeMenu(GtkWidget * widget)139 gboolean MainWindow::invokeMenu(GtkWidget* widget) {
140 // g_warning("invoke_menu %s", gtk_widget_get_name(widget));
141 gtk_widget_activate(widget);
142 return TRUE;
143 }
144
rebindAcceleratorsMenuItem(GtkWidget * widget,gpointer user_data)145 void MainWindow::rebindAcceleratorsMenuItem(GtkWidget* widget, gpointer user_data) {
146 if (GTK_IS_MENU_ITEM(widget)) {
147 GtkAccelGroup* newAccelGroup = reinterpret_cast<GtkAccelGroup*>(user_data);
148 GList* menuAccelClosures = gtk_widget_list_accel_closures(widget);
149 for (GList* l = menuAccelClosures; l != nullptr; l = l->next) {
150 GClosure* closure = reinterpret_cast<GClosure*>(l->data);
151 GtkAccelGroup* accelGroup = gtk_accel_group_from_accel_closure(closure);
152 GtkAccelKey* key = gtk_accel_group_find(accelGroup, isKeyForClosure, closure);
153
154 // g_warning("Rebind %s : %s", gtk_accelerator_get_label(key->accel_key, key->accel_mods),
155 // gtk_widget_get_name(widget));
156
157 gtk_accel_group_connect(newAccelGroup, key->accel_key, key->accel_mods, GtkAccelFlags(0),
158 g_cclosure_new_swap(G_CALLBACK(MainWindow::invokeMenu), widget, nullptr));
159 }
160
161 MainWindow::rebindAcceleratorsSubMenu(widget, newAccelGroup);
162 }
163 }
164
rebindAcceleratorsSubMenu(GtkWidget * widget,gpointer user_data)165 void MainWindow::rebindAcceleratorsSubMenu(GtkWidget* widget, gpointer user_data) {
166 if (GTK_IS_MENU_ITEM(widget)) {
167 GtkMenuItem* menuItem = reinterpret_cast<GtkMenuItem*>(widget);
168 GtkWidget* subMenu = gtk_menu_item_get_submenu(menuItem);
169 if (GTK_IS_CONTAINER(subMenu)) {
170 gtk_container_foreach(reinterpret_cast<GtkContainer*>(subMenu), rebindAcceleratorsMenuItem, user_data);
171 }
172 }
173 }
174
175 // When the Menubar is hidden, accelerators no longer work so rebind them to the MainWindow
176 // It should be called after all plugins have been initialised so that their injected menu items are captured
rebindMenubarAccelerators()177 void MainWindow::rebindMenubarAccelerators() {
178 this->globalAccelGroup = gtk_accel_group_new();
179 gtk_window_add_accel_group(GTK_WINDOW(this->getWindow()), this->globalAccelGroup);
180
181 GtkMenuBar* menuBar = (GtkMenuBar*)this->get("mainMenubar");
182 gtk_container_foreach(reinterpret_cast<GtkContainer*>(menuBar), rebindAcceleratorsSubMenu, this->globalAccelGroup);
183 }
184
~MainWindow()185 MainWindow::~MainWindow() {
186 for (int i = 0; i < TOOLBAR_DEFINITIONS_LEN; i++) {
187 g_object_unref(this->toolbarWidgets[i]);
188 }
189
190 delete[] this->toolbarWidgets;
191 this->toolbarWidgets = nullptr;
192
193 delete this->toolbarSelectMenu;
194 this->toolbarSelectMenu = nullptr;
195
196 delete this->floatingToolbox;
197 this->floatingToolbox = nullptr;
198
199 delete this->xournal;
200 this->xournal = nullptr;
201
202 delete this->toolbar;
203 this->toolbar = nullptr;
204
205 delete scrollHandling;
206 scrollHandling = nullptr;
207
208 g_object_unref(panedContainerWidget);
209 g_object_unref(boxContainerWidget);
210 g_object_unref(mainContentWidget);
211 g_object_unref(sidebarWidget);
212 }
213
214 /**
215 * Topmost widgets, to check if there is a menu above
216 */
217 const char* TOP_WIDGETS[] = {"tbTop1", "tbTop2", "mainContainerBox", nullptr};
218
219
toggleMenuBar(MainWindow * win)220 void MainWindow::toggleMenuBar(MainWindow* win) {
221 GtkWidget* menu = win->get("mainMenubar");
222 if (gtk_widget_is_visible(menu)) {
223 gtk_widget_hide(menu);
224 } else {
225 gtk_widget_show(menu);
226 }
227 }
228
updateColorscheme()229 void MainWindow::updateColorscheme() {
230 bool darkMode = control->getSettings()->isDarkTheme();
231 GtkStyleContext* context = gtk_widget_get_style_context(GTK_WIDGET(this->window));
232
233 if (darkMode) {
234 gtk_style_context_add_class(context, "darkMode");
235 } else {
236 gtk_style_context_remove_class(context, "darkMode");
237 }
238 }
239
initXournalWidget()240 void MainWindow::initXournalWidget() {
241 GtkWidget* boxContents = get("boxContents");
242
243
244 winXournal = gtk_scrolled_window_new(nullptr, nullptr);
245
246 setGtkTouchscreenScrollingForDeviceMapping();
247
248 gtk_container_add(GTK_CONTAINER(boxContents), winXournal);
249
250 GtkWidget* vpXournal = gtk_viewport_new(nullptr, nullptr);
251
252 gtk_container_add(GTK_CONTAINER(winXournal), vpXournal);
253
254 scrollHandling = new ScrollHandling(GTK_SCROLLABLE(vpXournal));
255
256 this->xournal = new XournalView(vpXournal, control, scrollHandling);
257
258 control->getZoomControl()->initZoomHandler(this->window, winXournal, xournal, control);
259 gtk_widget_show_all(winXournal);
260
261 Layout* layout = gtk_xournal_get_layout(this->xournal->getWidget());
262 scrollHandling->init(this->xournal->getWidget(), layout);
263
264 updateColorscheme();
265 }
266
setGtkTouchscreenScrollingForDeviceMapping()267 void MainWindow::setGtkTouchscreenScrollingForDeviceMapping() {
268 InputDeviceClass touchscreenClass =
269 DeviceListHelper::getSourceMapping(GDK_SOURCE_TOUCHSCREEN, this->getControl()->getSettings());
270
271 setGtkTouchscreenScrollingEnabled(touchscreenClass == INPUT_DEVICE_TOUCHSCREEN &&
272 !control->getSettings()->getTouchDrawingEnabled());
273 }
274
setGtkTouchscreenScrollingEnabled(bool enabled)275 void MainWindow::setGtkTouchscreenScrollingEnabled(bool enabled) {
276 if (enabled == gtkTouchscreenScrollingEnabled.load() || winXournal == nullptr) {
277 return;
278 }
279
280 gtkTouchscreenScrollingEnabled.store(enabled);
281
282 Util::execInUiThread(
283 [=]() {
284 gtk_scrolled_window_set_kinetic_scrolling(GTK_SCROLLED_WINDOW(winXournal),
285 gtkTouchscreenScrollingEnabled.load());
286 },
287 G_PRIORITY_HIGH);
288 }
289
getGtkTouchscreenScrollingEnabled() const290 bool MainWindow::getGtkTouchscreenScrollingEnabled() const { return gtkTouchscreenScrollingEnabled.load(); }
291
292 /**
293 * Allow to hide menubar, but only if global menu is not enabled
294 */
initHideMenu()295 void MainWindow::initHideMenu() {
296 int top = -1;
297 for (int i = 0; TOP_WIDGETS[i]; i++) {
298 GtkWidget* w = get(TOP_WIDGETS[i]);
299 GtkAllocation allocation;
300 gtk_widget_get_allocation(w, &allocation);
301 if (allocation.y != -1) {
302 top = allocation.y;
303 break;
304 }
305 }
306
307 GtkWidget* menuItem = get("menuHideMenu");
308 if (top < 5) {
309 // There is no menu to hide, the menu is in the globalmenu!
310 gtk_widget_hide(menuItem);
311 } else {
312 // Menu found, allow to hide it
313 g_signal_connect(menuItem, "activate",
314 G_CALLBACK(+[](GtkMenuItem* menuitem, MainWindow* self) { toggleMenuBar(self); }), this);
315 }
316
317 // Hide menubar at startup if specified in settings
318 Settings* settings = control->getSettings();
319 if (settings && !settings->isMenubarVisible()) {
320 toggleMenuBar(this);
321 }
322 }
323
getLayout()324 auto MainWindow::getLayout() -> Layout* { return gtk_xournal_get_layout(GTK_WIDGET(this->xournal->getWidget())); }
325
cancellable_cancel(GCancellable * cancel)326 auto cancellable_cancel(GCancellable* cancel) -> bool {
327 g_cancellable_cancel(cancel);
328
329 g_warning("Timeout... Cancel loading URL");
330
331 return false;
332 }
333
dragDataRecived(GtkWidget * widget,GdkDragContext * dragContext,gint x,gint y,GtkSelectionData * data,guint info,guint time,MainWindow * win)334 void MainWindow::dragDataRecived(GtkWidget* widget, GdkDragContext* dragContext, gint x, gint y, GtkSelectionData* data,
335 guint info, guint time, MainWindow* win) {
336 GtkWidget* source = gtk_drag_get_source_widget(dragContext);
337 if (source && widget == gtk_widget_get_toplevel(source)) {
338 gtk_drag_finish(dragContext, false, false, time);
339 return;
340 }
341
342 guchar* text = gtk_selection_data_get_text(data);
343 if (text) {
344 win->control->clipboardPasteText(reinterpret_cast<const char*>(text));
345
346 g_free(text);
347 gtk_drag_finish(dragContext, true, false, time);
348 return;
349 }
350
351 GdkPixbuf* image = gtk_selection_data_get_pixbuf(data);
352 if (image) {
353 win->control->clipboardPasteImage(image);
354
355 g_object_unref(image);
356 gtk_drag_finish(dragContext, true, false, time);
357 return;
358 }
359
360 gchar** uris = gtk_selection_data_get_uris(data);
361 if (uris) {
362 for (int i = 0; uris[i] != nullptr && i < 3; i++) {
363 const char* uri = uris[i];
364
365 GCancellable* cancel = g_cancellable_new();
366 int cancelTimeout = g_timeout_add(3000, reinterpret_cast<GSourceFunc>(cancellable_cancel), cancel);
367
368 GFile* file = g_file_new_for_uri(uri);
369 GError* err = nullptr;
370 GFileInputStream* in = g_file_read(file, cancel, &err);
371 if (g_cancellable_is_cancelled(cancel)) {
372 continue;
373 }
374
375 g_object_unref(file);
376 if (err == nullptr) {
377 GdkPixbuf* pixbuf = gdk_pixbuf_new_from_stream(G_INPUT_STREAM(in), cancel, nullptr);
378 if (g_cancellable_is_cancelled(cancel)) {
379 continue;
380 }
381 g_input_stream_close(G_INPUT_STREAM(in), cancel, nullptr);
382 if (g_cancellable_is_cancelled(cancel)) {
383 continue;
384 }
385
386 if (pixbuf) {
387 win->control->clipboardPasteImage(pixbuf);
388
389 g_object_unref(pixbuf);
390 }
391 } else {
392 g_error_free(err);
393 }
394
395 if (!g_cancellable_is_cancelled(cancel)) {
396 g_source_remove(cancelTimeout);
397 }
398 g_object_unref(cancel);
399 }
400
401 gtk_drag_finish(dragContext, true, false, time);
402
403 g_strfreev(uris);
404 }
405
406 gtk_drag_finish(dragContext, false, false, time);
407 }
408
viewShowSidebar(GtkCheckMenuItem * checkmenuitem,MainWindow * win)409 void MainWindow::viewShowSidebar(GtkCheckMenuItem* checkmenuitem, MainWindow* win) {
410 bool a = gtk_check_menu_item_get_active(checkmenuitem);
411 if (win->control->getSettings()->isSidebarVisible() == a) {
412 return;
413 }
414 win->setSidebarVisible(a);
415 }
416
viewShowToolbar(GtkCheckMenuItem * checkmenuitem,MainWindow * win)417 void MainWindow::viewShowToolbar(GtkCheckMenuItem* checkmenuitem, MainWindow* win) {
418 bool showToolbar = gtk_check_menu_item_get_active(checkmenuitem);
419 if (win->control->getSettings()->isToolbarVisible() == showToolbar) {
420 return;
421 }
422 win->setToolbarVisible(showToolbar);
423 }
424
getControl()425 auto MainWindow::getControl() -> Control* { return control; }
426
updateScrollbarSidebarPosition()427 void MainWindow::updateScrollbarSidebarPosition() {
428 GtkWidget* panelMainContents = get("panelMainContents");
429
430 if (winXournal != nullptr) {
431 GtkScrolledWindow* scrolledWindow = GTK_SCROLLED_WINDOW(winXournal);
432
433 ScrollbarHideType type = this->getControl()->getSettings()->getScrollbarHideType();
434
435 bool scrollbarOnLeft = control->getSettings()->isScrollbarOnLeft();
436 if (scrollbarOnLeft) {
437 gtk_scrolled_window_set_placement(scrolledWindow, GTK_CORNER_TOP_RIGHT);
438 } else {
439 gtk_scrolled_window_set_placement(scrolledWindow, GTK_CORNER_TOP_LEFT);
440 }
441
442 gtk_widget_set_visible(gtk_scrolled_window_get_hscrollbar(scrolledWindow), !(type & SCROLLBAR_HIDE_HORIZONTAL));
443 gtk_widget_set_visible(gtk_scrolled_window_get_vscrollbar(scrolledWindow), !(type & SCROLLBAR_HIDE_VERTICAL));
444
445 gtk_scrolled_window_set_overlay_scrolling(scrolledWindow,
446 !control->getSettings()->isScrollbarFadeoutDisabled());
447 }
448
449 // If the sidebar isn't visible, we can't change its position!
450 if (!this->sidebarVisible) {
451 return;
452 }
453
454 GtkWidget* sidebar = get("sidebar");
455 GtkWidget* boxContents = get("boxContents");
456
457 int divider = gtk_paned_get_position(GTK_PANED(panelMainContents));
458 bool sidebarRight = control->getSettings()->isSidebarOnRight();
459 if (sidebarRight == (gtk_paned_get_child2(GTK_PANED(panelMainContents)) == sidebar)) {
460 // Already correct
461 return;
462 }
463
464
465 GtkAllocation allocation;
466 gtk_widget_get_allocation(panelMainContents, &allocation);
467 divider = allocation.width - divider;
468
469
470 g_object_ref(sidebar);
471 g_object_ref(boxContents);
472
473 gtk_container_remove(GTK_CONTAINER(panelMainContents), sidebar);
474 gtk_container_remove(GTK_CONTAINER(panelMainContents), boxContents);
475
476 if (sidebarRight) {
477 gtk_paned_pack1(GTK_PANED(panelMainContents), boxContents, true, false);
478 gtk_paned_pack2(GTK_PANED(panelMainContents), sidebar, false, false);
479 } else {
480 gtk_paned_pack1(GTK_PANED(panelMainContents), sidebar, false, false);
481 gtk_paned_pack2(GTK_PANED(panelMainContents), boxContents, true, false);
482 }
483
484 gtk_paned_set_position(GTK_PANED(panelMainContents), divider);
485 g_object_unref(sidebar);
486 g_object_unref(boxContents);
487 }
488
buttonCloseSidebarClicked(GtkButton * button,MainWindow * win)489 void MainWindow::buttonCloseSidebarClicked(GtkButton* button, MainWindow* win) { win->setSidebarVisible(false); }
490
onKeyPressCallback(GtkWidget * widget,GdkEventKey * event,MainWindow * win)491 auto MainWindow::onKeyPressCallback(GtkWidget* widget, GdkEventKey* event, MainWindow* win) -> bool {
492
493 if (win->getXournal()->getSelection()) {
494 // something is selected - give that control
495 return false;
496 }
497 if (win->getXournal()->getTextEditor()) {
498 // editing text - give that control
499 return false;
500 }
501 if (event->keyval == GDK_KEY_Escape) {
502 win->getControl()->getSearchBar()->showSearchBar(false);
503 return true;
504 }
505
506
507 return false;
508 }
509
deleteEventCallback(GtkWidget * widget,GdkEvent * event,Control * control)510 auto MainWindow::deleteEventCallback(GtkWidget* widget, GdkEvent* event, Control* control) -> bool {
511 control->quit();
512
513 return true;
514 }
515
setSidebarVisible(bool visible)516 void MainWindow::setSidebarVisible(bool visible) {
517 Settings* settings = control->getSettings();
518
519 settings->setSidebarVisible(visible);
520 if (!visible && (control->getSidebar() != nullptr)) {
521 saveSidebarSize();
522 }
523
524 if (visible != this->sidebarVisible) {
525 // Due to a GTK bug, we can't just hide the sidebar widget in the GtkPaned.
526 // If we do this, we create a dead region where the pane separator was previously.
527 // In this region, we can't use the touchscreen to start horizontal strokes.
528 // As such:
529 if (!visible) {
530 gtk_container_remove(GTK_CONTAINER(panedContainerWidget), mainContentWidget);
531 gtk_container_remove(GTK_CONTAINER(boxContainerWidget), GTK_WIDGET(panedContainerWidget));
532 gtk_container_add(GTK_CONTAINER(boxContainerWidget), mainContentWidget);
533 this->sidebarVisible = false;
534 } else {
535 gtk_container_remove(GTK_CONTAINER(boxContainerWidget), mainContentWidget);
536 gtk_container_add(GTK_CONTAINER(panedContainerWidget), mainContentWidget);
537 gtk_container_add(GTK_CONTAINER(boxContainerWidget), GTK_WIDGET(panedContainerWidget));
538 this->sidebarVisible = true;
539
540 updateScrollbarSidebarPosition();
541 }
542 }
543
544 gtk_widget_set_visible(sidebarWidget, visible);
545
546 if (visible) {
547 gtk_paned_set_position(GTK_PANED(panedContainerWidget), settings->getSidebarWidth());
548 }
549
550 GtkWidget* w = get("menuViewSidebarVisible");
551 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w), visible);
552 }
553
setToolbarVisible(bool visible)554 void MainWindow::setToolbarVisible(bool visible) {
555 Settings* settings = control->getSettings();
556
557 settings->setToolbarVisible(visible);
558 for (int i = 0; i < TOOLBAR_DEFINITIONS_LEN; i++) {
559 auto widget = this->toolbarWidgets[i];
560 if (!visible || GTK_IS_CONTAINER(widget) && gtk_container_get_children(GTK_CONTAINER(widget))) {
561 gtk_widget_set_visible(widget, visible);
562 }
563 }
564
565 GtkWidget* w = get("menuViewToolbarsVisible");
566 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w), visible);
567 }
568
saveSidebarSize()569 void MainWindow::saveSidebarSize() {
570 this->control->getSettings()->setSidebarWidth(gtk_paned_get_position(GTK_PANED(panedContainerWidget)));
571 }
572
setMaximized(bool maximized)573 void MainWindow::setMaximized(bool maximized) { this->maximized = maximized; }
574
isMaximized() const575 auto MainWindow::isMaximized() const -> bool { return this->maximized; }
576
getXournal()577 auto MainWindow::getXournal() -> XournalView* { return xournal; }
578
windowStateEventCallback(GtkWidget * window,GdkEventWindowState * event,MainWindow * win)579 auto MainWindow::windowStateEventCallback(GtkWidget* window, GdkEventWindowState* event, MainWindow* win) -> bool {
580 win->setMaximized(gtk_window_is_maximized(GTK_WINDOW(window)));
581
582 return false;
583 }
584
reloadToolbars()585 void MainWindow::reloadToolbars() {
586 bool inDragAndDrop = this->control->isInDragAndDropToolbar();
587
588 ToolbarData* d = getSelectedToolbar();
589
590 if (inDragAndDrop) {
591 this->control->endDragDropToolbar();
592 }
593
594 this->clearToolbar();
595 this->toolbarSelected(d);
596
597 if (inDragAndDrop) {
598 this->control->startDragDropToolbar();
599 }
600 }
601
toolbarSelected(ToolbarData * d)602 void MainWindow::toolbarSelected(ToolbarData* d) {
603 if (!this->toolbarIntialized || this->selectedToolbar == d) {
604 return;
605 }
606
607 Settings* settings = control->getSettings();
608 settings->setSelectedToolbar(d->getId());
609
610 this->clearToolbar();
611 this->loadToolbar(d);
612 }
613
clearToolbar()614 auto MainWindow::clearToolbar() -> ToolbarData* {
615 if (this->selectedToolbar != nullptr) {
616 for (int i = 0; i < TOOLBAR_DEFINITIONS_LEN; i++) {
617 ToolMenuHandler::unloadToolbar(this->toolbarWidgets[i]);
618 }
619
620 this->toolbar->freeDynamicToolbarItems();
621 }
622
623 ToolbarData* oldData = this->selectedToolbar;
624
625 this->selectedToolbar = nullptr;
626
627 return oldData;
628 }
629
loadToolbar(ToolbarData * d)630 void MainWindow::loadToolbar(ToolbarData* d) {
631 this->selectedToolbar = d;
632
633 for (int i = 0; i < TOOLBAR_DEFINITIONS_LEN; i++) {
634 this->toolbar->load(d, this->toolbarWidgets[i], TOOLBAR_DEFINITIONS[i].propName,
635 TOOLBAR_DEFINITIONS[i].horizontal);
636 }
637
638 this->floatingToolbox->flagRecalculateSizeRequired();
639 }
640
getSelectedToolbar()641 auto MainWindow::getSelectedToolbar() -> ToolbarData* { return this->selectedToolbar; }
642
getToolbarWidgets(int & length)643 auto MainWindow::getToolbarWidgets(int& length) -> GtkWidget** {
644 length = TOOLBAR_DEFINITIONS_LEN;
645 return this->toolbarWidgets;
646 }
647
getToolbarName(GtkToolbar * toolbar)648 auto MainWindow::getToolbarName(GtkToolbar* toolbar) -> const char* {
649 for (int i = 0; i < TOOLBAR_DEFINITIONS_LEN; i++) {
650 if (static_cast<void*>(this->toolbarWidgets[i]) == static_cast<void*>(toolbar)) {
651 return TOOLBAR_DEFINITIONS[i].propName;
652 }
653 }
654
655 return "";
656 }
657
setControlTmpDisabled(bool disabled)658 void MainWindow::setControlTmpDisabled(bool disabled) {
659 toolbar->setTmpDisabled(disabled);
660 toolbarSelectMenu->setTmpDisabled(disabled);
661
662 GtkWidget* menuFileRecent = get("menuFileRecent");
663 gtk_widget_set_sensitive(menuFileRecent, !disabled);
664 }
665
updateToolbarMenu()666 void MainWindow::updateToolbarMenu() { createToolbarAndMenu(); }
667
createToolbarAndMenu()668 void MainWindow::createToolbarAndMenu() {
669 GtkMenuShell* menubar = GTK_MENU_SHELL(get("menuViewToolbar"));
670 g_return_if_fail(menubar != nullptr);
671
672 toolbarSelectMenu->updateToolbarMenu(menubar, control->getSettings(), toolbar);
673
674 ToolbarData* td = toolbarSelectMenu->getSelectedToolbar();
675 if (td) {
676 this->toolbarIntialized = true;
677 toolbarSelected(td);
678 }
679
680 if (!this->control->getAudioController()->isPlaying()) {
681 this->getToolMenuHandler()->disableAudioPlaybackButtons();
682 }
683
684 this->control->getScheduler()->unblockRerenderZoom();
685 }
686
setFontButtonFont(XojFont & font)687 void MainWindow::setFontButtonFont(XojFont& font) { toolbar->setFontButtonFont(font); }
688
getFontButtonFont()689 auto MainWindow::getFontButtonFont() -> XojFont { return toolbar->getFontButtonFont(); }
690
updatePageNumbers(size_t page,size_t pagecount,size_t pdfpage)691 void MainWindow::updatePageNumbers(size_t page, size_t pagecount, size_t pdfpage) {
692 SpinPageAdapter* spinPageNo = getSpinPageNo();
693
694 size_t min = 0;
695 size_t max = pagecount;
696
697 if (pagecount == 0) {
698 min = 0;
699 page = 0;
700 } else {
701 min = 1;
702 page++;
703 }
704
705 spinPageNo->setMinMaxPage(min, max);
706 spinPageNo->setPage(page);
707
708 if (pdfpage != npos) {
709 toolbar->setPageInfo(pagecount, pdfpage + 1);
710 } else {
711 toolbar->setPageInfo(pagecount);
712 }
713 }
714
rebuildLayerMenu()715 void MainWindow::rebuildLayerMenu() { layerVisibilityChanged(); }
716
layerVisibilityChanged()717 void MainWindow::layerVisibilityChanged() {
718 LayerController* lc = control->getLayerController();
719
720 int layer = lc->getCurrentLayerId();
721 int maxLayer = lc->getLayerCount();
722
723 control->fireEnableAction(ACTION_DELETE_LAYER, layer > 0);
724 control->fireEnableAction(ACTION_GOTO_NEXT_LAYER, layer < maxLayer);
725 control->fireEnableAction(ACTION_GOTO_PREVIOUS_LAYER, layer > 0);
726 control->fireEnableAction(ACTION_GOTO_TOP_LAYER, layer < maxLayer);
727 }
728
setRecentMenu(GtkWidget * submenu)729 void MainWindow::setRecentMenu(GtkWidget* submenu) {
730 GtkWidget* menuitem = get("menuFileRecent");
731 g_return_if_fail(menuitem != nullptr);
732 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu);
733 }
734
show(GtkWindow * parent)735 void MainWindow::show(GtkWindow* parent) { gtk_widget_show(this->window); }
736
setUndoDescription(const string & description)737 void MainWindow::setUndoDescription(const string& description) { toolbar->setUndoDescription(description); }
738
setRedoDescription(const string & description)739 void MainWindow::setRedoDescription(const string& description) { toolbar->setRedoDescription(description); }
740
getSpinPageNo()741 auto MainWindow::getSpinPageNo() -> SpinPageAdapter* { return toolbar->getPageSpinner(); }
742
getToolbarModel()743 auto MainWindow::getToolbarModel() -> ToolbarModel* { return this->toolbar->getModel(); }
744
getToolMenuHandler()745 auto MainWindow::getToolMenuHandler() -> ToolMenuHandler* { return this->toolbar; }
746
disableAudioPlaybackButtons()747 void MainWindow::disableAudioPlaybackButtons() {
748 setAudioPlaybackPaused(false);
749
750 this->getToolMenuHandler()->disableAudioPlaybackButtons();
751 }
752
enableAudioPlaybackButtons()753 void MainWindow::enableAudioPlaybackButtons() { this->getToolMenuHandler()->enableAudioPlaybackButtons(); }
754
setAudioPlaybackPaused(bool paused)755 void MainWindow::setAudioPlaybackPaused(bool paused) { this->getToolMenuHandler()->setAudioPlaybackPaused(paused); }
756
loadMainCSS(GladeSearchpath * gladeSearchPath,const gchar * cssFilename)757 void MainWindow::loadMainCSS(GladeSearchpath* gladeSearchPath, const gchar* cssFilename) {
758 auto filepath = gladeSearchPath->findFile("", cssFilename);
759 GtkCssProvider* provider = gtk_css_provider_new();
760 gtk_css_provider_load_from_path(provider, filepath.u8string().c_str(), nullptr);
761 gtk_style_context_add_provider_for_screen(gdk_screen_get_default(), GTK_STYLE_PROVIDER(provider),
762 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
763 g_object_unref(provider);
764 }
765