1 /* GSequencer - Advanced GTK Sequencer
2  * Copyright (C) 2005-2020 Joël Krähemann
3  *
4  * This file is part of GSequencer.
5  *
6  * GSequencer is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GSequencer is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with GSequencer.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <ags/X/ags_online_help_window.h>
21 #include <ags/X/ags_online_help_window_callbacks.h>
22 
23 #include <ags/X/ags_ui_provider.h>
24 #include <ags/X/ags_window.h>
25 
26 #include <stdlib.h>
27 #include <string.h>
28 
29 #include <ags/i18n.h>
30 
31 void ags_online_help_window_class_init(AgsOnlineHelpWindowClass *online_help_window);
32 void ags_online_help_window_connectable_interface_init(AgsConnectableInterface *connectable);
33 void ags_online_help_window_init(AgsOnlineHelpWindow *online_help_window);
34 
35 void ags_online_help_window_connect(AgsConnectable *connectable);
36 void ags_online_help_window_disconnect(AgsConnectable *connectable);
37 
38 gboolean ags_online_help_window_delete_event(GtkWidget *widget, GdkEventAny *event);
39 
40 static gpointer ags_online_help_window_parent_class = NULL;
41 
42 GType
ags_online_help_window_get_type()43 ags_online_help_window_get_type()
44 {
45   static volatile gsize g_define_type_id__volatile = 0;
46 
47   if(g_once_init_enter (&g_define_type_id__volatile)){
48     GType ags_type_online_help_window = 0;
49 
50     static const GTypeInfo ags_online_help_window_info = {
51       sizeof (AgsOnlineHelpWindowClass),
52       NULL, /* base_init */
53       NULL, /* base_finalize */
54       (GClassInitFunc) ags_online_help_window_class_init,
55       NULL, /* class_finalize */
56       NULL, /* class_data */
57       sizeof (AgsOnlineHelpWindow),
58       0,    /* n_preallocs */
59       (GInstanceInitFunc) ags_online_help_window_init,
60     };
61 
62     static const GInterfaceInfo ags_connectable_interface_info = {
63       (GInterfaceInitFunc) ags_online_help_window_connectable_interface_init,
64       NULL, /* interface_finalize */
65       NULL, /* interface_data */
66     };
67 
68     ags_type_online_help_window = g_type_register_static(GTK_TYPE_WINDOW,
69 							 "AgsOnlineHelpWindow", &ags_online_help_window_info,
70 							 0);
71 
72     g_type_add_interface_static(ags_type_online_help_window,
73 				AGS_TYPE_CONNECTABLE,
74 				&ags_connectable_interface_info);
75 
76     g_once_init_leave(&g_define_type_id__volatile, ags_type_online_help_window);
77   }
78 
79   return g_define_type_id__volatile;
80 }
81 
82 void
ags_online_help_window_class_init(AgsOnlineHelpWindowClass * online_help_window)83 ags_online_help_window_class_init(AgsOnlineHelpWindowClass *online_help_window)
84 {
85   GtkWidgetClass *widget;
86 
87   ags_online_help_window_parent_class = g_type_class_peek_parent(online_help_window);
88 
89   /* GtkWidgetClass */
90   widget = (GtkWidgetClass *) online_help_window;
91 
92   widget->delete_event = ags_online_help_window_delete_event;
93 }
94 
95 void
ags_online_help_window_connectable_interface_init(AgsConnectableInterface * connectable)96 ags_online_help_window_connectable_interface_init(AgsConnectableInterface *connectable)
97 {
98   connectable->get_uuid = NULL;
99   connectable->has_resource = NULL;
100 
101   connectable->is_ready = NULL;
102   connectable->add_to_registry = NULL;
103   connectable->remove_from_registry = NULL;
104 
105   connectable->list_resource = NULL;
106 
107   connectable->xml_compose = NULL;
108   connectable->xml_parse = NULL;
109 
110   connectable->is_connected = NULL;
111   connectable->connect = ags_online_help_window_connect;
112   connectable->disconnect = ags_online_help_window_disconnect;
113 
114   connectable->connect_connection = NULL;
115   connectable->disconnect_connection = NULL;
116 }
117 
118 void
ags_online_help_window_init(AgsOnlineHelpWindow * online_help_window)119 ags_online_help_window_init(AgsOnlineHelpWindow *online_help_window)
120 {
121 #if defined(AGS_WITH_WEBKIT)
122   GtkBox *vbox;
123   GtkBox *navigation_hbox;
124   GtkLabel *label;
125 
126   gchar *start_filename;
127 
128   g_object_set(online_help_window,
129 	       "title", i18n("online help"),
130 	       NULL);
131 
132   g_object_set(online_help_window,
133 	       "default-width", 800,
134 	       "default-height", 600,
135 	       NULL);
136 
137   vbox = (GtkBox *) gtk_box_new(GTK_ORIENTATION_VERTICAL,
138 				0);
139   gtk_container_add((GtkContainer *) online_help_window,
140 		    (GtkWidget *) vbox);
141 
142   /* navigation */
143   navigation_hbox = (GtkBox *) gtk_box_new(GTK_ORIENTATION_HORIZONTAL,
144 					   0);
145   gtk_box_pack_start((GtkBox *) vbox,
146 		     (GtkWidget *) navigation_hbox,
147 		     FALSE, FALSE,
148 		     0);
149 
150   online_help_window->home = (GtkButton *) gtk_button_new_from_icon_name("go-home",
151 									 GTK_ICON_SIZE_BUTTON);
152   gtk_box_pack_start((GtkBox *) navigation_hbox,
153 		     (GtkWidget *) online_help_window->home,
154 		     FALSE, FALSE,
155 		     0);
156 
157   online_help_window->prev = (GtkButton *) gtk_button_new_from_icon_name("go-previous",
158 									 GTK_ICON_SIZE_BUTTON);
159   gtk_box_pack_start((GtkBox *) navigation_hbox,
160 		     (GtkWidget *) online_help_window->prev,
161 		     FALSE, FALSE,
162 		     0);
163 
164   online_help_window->next = (GtkButton *) gtk_button_new_from_icon_name("go-next",
165 									 GTK_ICON_SIZE_BUTTON);
166   gtk_box_pack_start((GtkBox *) navigation_hbox,
167 		     (GtkWidget *) online_help_window->next,
168 		     FALSE, FALSE,
169 		     0);
170 
171   label = (GtkLabel *) gtk_label_new(i18n("Place"));
172   gtk_box_pack_start((GtkBox *) navigation_hbox,
173 		     (GtkWidget *) label,
174 		     FALSE, FALSE,
175 		     0);
176 
177   online_help_window->location = (GtkEntry *) gtk_entry_new();
178   gtk_box_pack_start((GtkBox *) navigation_hbox,
179 		     (GtkWidget *) online_help_window->location,
180 		     FALSE, FALSE,
181 		     0);
182 
183   /* webkit */
184   start_filename = NULL;
185 
186 #if defined(AGS_ONLINE_HELP_START_FILENAME)
187   start_filename = g_strdup(AGS_ONLINE_HELP_START_FILENAME);
188 #else
189   if((start_filename = getenv("AGS_ONLINE_HELP_START_FILENAME")) != NULL){
190     start_filename = g_strdup(start_filename);
191   }else{
192 #if defined (AGS_W32API)
193     AgsApplicationContext *application_context;
194 
195     gchar *app_dir;
196 
197     application_context = ags_application_context_get_instance();
198 
199     app_dir = NULL;
200 
201     if(strlen(application_context->argv[0]) > strlen("\\gsequencer.exe")){
202       app_dir = g_strndup(application_context->argv[0],
203 			  strlen(application_context->argv[0]) - strlen("\\gsequencer.exe"));
204     }
205 
206     start_filename = g_strdup_printf("%s\\share\\doc\\gsequencer-doc\\html\\index.html",
207 				     g_get_current_dir());
208 
209     if(!g_file_test(start_filename,
210 		    G_FILE_TEST_IS_REGULAR)){
211       g_free(start_filename);
212 
213       if(g_path_is_absolute(app_dir)){
214 	start_filename = g_strdup_printf("%s\\%s",
215 					 app_dir,
216 					 "\\share\\doc\\gsequencer-doc\\html\\index.html");
217       }else{
218 	start_filename = g_strdup_printf("%s\\%s\\%s",
219 					 g_get_current_dir(),
220 					 app_dir,
221 					 "\\share\\doc\\gsequencer-doc\\html\\index.html");
222       }
223     }
224 
225     g_free(app_dir);
226 #else
227 #if defined(AGS_WITH_SINGLE_DOCDIR)
228     start_filename = g_strdup_printf("file://%s/user-manual/index.html",
229 				     DOCDIR);
230 #else
231     start_filename = g_strdup_printf("file://%s/doc/gsequencer-doc/html/index.html",
232 				     DESTDIR);
233 #endif
234 #endif
235   }
236 #endif /* defined(AGS_ONLINE_HELP_START_FILENAME) */
237 
238   online_help_window->web_view = WEBKIT_WEB_VIEW(webkit_web_view_new());
239   gtk_box_pack_start((GtkBox *) vbox,
240 		     GTK_WIDGET(online_help_window->web_view),
241 		     TRUE, TRUE,
242 		     0);
243 
244   g_signal_connect(GTK_WIDGET(online_help_window->web_view), "load-changed",
245 		   G_CALLBACK(ags_online_help_window_load_changed), online_help_window);
246 
247   online_help_window->start_filename = start_filename;
248 
249   webkit_web_view_load_uri(online_help_window->web_view,
250 			   start_filename);
251 #else
252 #if defined(AGS_WITH_POPPLER)
253   GtkVBox *vbox;
254   GtkGrid *grid;
255 
256   GtkAdjustment *vadjustment, *hadjustment;
257   GtkAllocation allocation;
258 
259   cairo_t *cr;
260 
261   gchar *data;
262   gchar *pdf_filename;
263 
264   gsize length;
265   gint num_pages, i;
266   gdouble width, height;
267   gint max_width, max_height;
268 
269   GError *error;
270 
271   g_object_set(online_help_window,
272 	       "title", i18n("online help"),
273 	       NULL);
274 
275   width = 800.0;
276   height = 600.0;
277 
278   g_object_set(online_help_window,
279 	       "default-width", (gint) width,
280 	       "default-height", (gint) height,
281 	       NULL);
282 
283   vbox = (GtkVBox *) gtk_vbox_new(FALSE,
284 				  0);
285   gtk_container_add((GtkContainer *) online_help_window,
286 		    (GtkWidget *) vbox);
287 
288   grid = gtk_grid_new();
289   gtk_box_pack_start((GtkBox *) vbox,
290 		     (GtkWidget *) grid,
291 		     TRUE, TRUE,
292 		     0);
293 
294   online_help_window->pdf_drawing_area = (GtkDrawingArea *) gtk_drawing_area_new();
295   gtk_widget_set_vexpand(online_help_window->pdf_drawing_area,
296 			 TRUE);
297   gtk_widget_set_hexpand(online_help_window->pdf_drawing_area,
298 			 TRUE);
299 
300   gtk_grid_attach(grid,
301 		  (GtkWidget *) online_help_window->pdf_drawing_area,
302 		  0, 0,
303 		  1, 1);
304 
305   vadjustment = gtk_adjustment_new(0.0, 0.0, 1.0, 0.1, 0.2, 1.0);
306 
307   online_help_window->pdf_vscrollbar = gtk_vscrollbar_new(vadjustment);
308   gtk_grid_attach(grid,
309 		  (GtkWidget *) online_help_window->pdf_vscrollbar,
310 		  1, 0,
311 		  1, 1);
312 
313   hadjustment = gtk_adjustment_new(0.0, 0.0, 1.0, 0.1, 0.2, 1.0);
314 
315   online_help_window->pdf_hscrollbar = gtk_hscrollbar_new(hadjustment);
316   gtk_grid_attach(grid,
317 		  (GtkWidget *) online_help_window->pdf_hscrollbar,
318 		  0, 1,
319 		  1, 1);
320 
321 #ifdef AGS_ONLINE_HELP_PDF_FILENAME
322   pdf_filename = g_strdup(AGS_ONLINE_HELP_PDF_FILENAME);
323 #else
324   if((pdf_filename = getenv("AGS_ONLINE_HELP_PDF_FILENAME")) != NULL){
325     pdf_filename = g_strdup(pdf_filename);
326   }else{
327 #if defined (AGS_W32API)
328     AgsApplicationContext *application_context;
329 
330     gchar *app_dir;
331 
332     application_context = ags_application_context_get_instance();
333 
334     app_dir = NULL;
335 
336     if(strlen(application_context->argv[0]) > strlen("\\gsequencer.exe")){
337       app_dir = g_strndup(application_context->argv[0],
338 			  strlen(application_context->argv[0]) - strlen("\\gsequencer.exe"));
339     }
340 
341     pdf_filename = g_strdup_printf("%s\\share\\doc\\gsequencer-doc\\pdf\\ags-user-manual.pdf",
342 				   g_get_current_dir());
343 
344     if(!g_file_test(pdf_filename,
345 		    G_FILE_TEST_IS_REGULAR)){
346       g_free(pdf_filename);
347 
348       if(g_path_is_absolute(app_dir)){
349 	pdf_filename = g_strdup_printf("%s\\%s",
350 				       app_dir,
351 				       "\\share\\doc\\gsequencer-doc\\pdf\\ags-user-manual.pdf");
352       }else{
353 	pdf_filename = g_strdup_printf("%s\\%s\\%s",
354 				       g_get_current_dir(),
355 				       app_dir,
356 				       "\\share\\doc\\gsequencer-doc\\pdf\\ags-user-manual.pdf");
357       }
358     }
359 
360     g_free(app_dir);
361 #else
362     pdf_filename = g_strdup_printf("%s%s", DOCDIR, "/pdf/user-manual.pdf");
363 #endif
364   }
365 #endif
366 
367   error = NULL;
368   g_file_get_contents(pdf_filename,
369 		      &data,
370 		      &length,
371 		      &error);
372 
373   error = NULL;
374   online_help_window->pdf_document = poppler_document_new_from_data(data,
375 								    length,
376 								    NULL,
377 								    &error);
378 
379   num_pages = poppler_document_get_n_pages(online_help_window->pdf_document);
380 
381   max_width = 0;
382   max_height = 0;
383 
384   for(i = 0; i < num_pages; i++){
385     PopplerPage *page;
386 
387     page = poppler_document_get_page(online_help_window->pdf_document,
388 				     i);
389 
390     if(page == NULL) {
391       g_warning("poppler fail: page not found");
392 
393       break;
394     }
395 
396     poppler_page_get_size(page,
397 			  &width, &height);
398 
399     if(max_width < width){
400       max_width = width;
401     }
402 
403     max_height += height;
404 
405     g_object_unref(page);
406   }
407 
408   online_help_window->max_height = max_height;
409   online_help_window->max_width = max_width;
410 
411   gtk_widget_get_allocation(online_help_window->pdf_drawing_area,
412 			    &allocation);
413 
414   gtk_adjustment_configure(vadjustment,
415 			   0.0,
416 			   0.0,
417 			   (double) online_help_window->max_height - (double) allocation.height,
418 			   5.0,
419 			   15.0,
420 			   (double) 10.0);
421 
422   gtk_adjustment_configure(hadjustment,
423 			   0.0,
424 			   0.0,
425 			   (double) online_help_window->max_width - (double) allocation.width,
426 			   5.0,
427 			   15.0,
428 			   (double) 100.0);
429 #endif
430 #endif
431 }
432 
433 void
ags_online_help_window_connect(AgsConnectable * connectable)434 ags_online_help_window_connect(AgsConnectable *connectable)
435 {
436   AgsOnlineHelpWindow *online_help_window;
437 
438   online_help_window = AGS_ONLINE_HELP_WINDOW(connectable);
439 
440   if((AGS_ONLINE_HELP_WINDOW_CONNECTED & (online_help_window->flags)) != 0){
441     return;
442   }
443 
444   online_help_window->flags |= AGS_ONLINE_HELP_WINDOW_CONNECTED;
445 
446 #if defined(AGS_WITH_WEBKIT)
447   g_signal_connect(G_OBJECT(online_help_window->home), "clicked",
448 		   G_CALLBACK(ags_online_help_window_home_callback), online_help_window);
449 
450   g_signal_connect(G_OBJECT(online_help_window->next), "clicked",
451 		   G_CALLBACK(ags_online_help_window_next_callback), online_help_window);
452 
453   g_signal_connect(G_OBJECT(online_help_window->prev), "clicked",
454 		   G_CALLBACK(ags_online_help_window_prev_callback), online_help_window);
455 #else
456 #if defined(AGS_WITH_POPPLER)
457   g_signal_connect_after(G_OBJECT(online_help_window->pdf_drawing_area), "draw",
458 			 G_CALLBACK(ags_online_help_window_pdf_drawing_area_draw_callback), online_help_window);
459 
460   g_signal_connect_after(G_OBJECT(online_help_window->pdf_drawing_area), "configure-event",
461 			 G_CALLBACK(ags_online_help_window_pdf_drawing_area_configure_callback), online_help_window);
462 
463   g_signal_connect_after(G_OBJECT(online_help_window->pdf_vscrollbar), "value-changed",
464 			 G_CALLBACK(ags_online_help_window_pdf_vscrollbar_value_changed_callback), online_help_window);
465 
466   g_signal_connect_after(G_OBJECT(online_help_window->pdf_hscrollbar), "value-changed",
467 			 G_CALLBACK(ags_online_help_window_pdf_hscrollbar_value_changed_callback), online_help_window);
468 #endif
469 #endif
470 }
471 
472 void
ags_online_help_window_disconnect(AgsConnectable * connectable)473 ags_online_help_window_disconnect(AgsConnectable *connectable)
474 {
475   AgsOnlineHelpWindow *online_help_window;
476 
477   online_help_window = AGS_ONLINE_HELP_WINDOW(connectable);
478 
479   if((AGS_ONLINE_HELP_WINDOW_CONNECTED & (online_help_window->flags)) == 0){
480     return;
481   }
482 
483   online_help_window->flags &= (~AGS_ONLINE_HELP_WINDOW_CONNECTED);
484 
485 #if defined(AGS_WITH_WEBKIT)
486   g_object_disconnect(G_OBJECT(online_help_window->home),
487 		      "any_signal::clicked",
488 		      G_CALLBACK(ags_online_help_window_home_callback),
489 		      online_help_window,
490 		      NULL);
491 
492   g_object_disconnect(G_OBJECT(online_help_window->next),
493 		      "any_signal::clicked",
494 		      G_CALLBACK(ags_online_help_window_next_callback),
495 		      online_help_window,
496 		      NULL);
497 
498   g_object_disconnect(G_OBJECT(online_help_window->prev),
499 		      "any_signal::clicked",
500 		      G_CALLBACK(ags_online_help_window_prev_callback),
501 		      online_help_window,
502 		      NULL);
503 #else
504 #if defined(AGS_WITH_POPPLER)
505   g_object_disconnect(G_OBJECT(online_help_window->pdf_drawing_area),
506 		      "any_signal::draw",
507 		      G_CALLBACK(ags_online_help_window_pdf_drawing_area_draw_callback),
508 		      online_help_window,
509 		      "any_signal::configure-event",
510 		      G_CALLBACK(ags_online_help_window_pdf_drawing_area_configure_callback),
511 		      online_help_window,
512 		      NULL);
513 
514   g_object_disconnect(G_OBJECT(online_help_window->pdf_vscrollbar),
515 		      "value-changed",
516 		      G_CALLBACK(ags_online_help_window_pdf_vscrollbar_value_changed_callback),
517 		      online_help_window,
518 		      NULL);
519 
520   g_object_disconnect(G_OBJECT(online_help_window->pdf_hscrollbar),
521 		      "value-changed",
522 		      G_CALLBACK(ags_online_help_window_pdf_hscrollbar_value_changed_callback),
523 		      online_help_window,
524 		      NULL);
525 #endif
526 #endif
527 }
528 
529 gboolean
ags_online_help_window_delete_event(GtkWidget * widget,GdkEventAny * event)530 ags_online_help_window_delete_event(GtkWidget *widget, GdkEventAny *event)
531 {
532   gtk_widget_hide(widget);
533 
534   return(TRUE);
535 }
536 
537 /**
538  * ags_online_help_window_new:
539  *
540  * Creates an #AgsOnlineHelpWindow
541  *
542  * Returns: a new #AgsOnlineHelpWindow
543  *
544  * Since: 3.5.0
545  */
546 AgsOnlineHelpWindow*
ags_online_help_window_new()547 ags_online_help_window_new()
548 {
549   AgsOnlineHelpWindow *online_help_window;
550 
551   online_help_window = (AgsOnlineHelpWindow *) g_object_new(AGS_TYPE_ONLINE_HELP_WINDOW,
552 							    NULL);
553 
554   return(online_help_window);
555 }
556