add playlist scrollbar
[uwplayer.git] / application / main.c
1 /*
2  * Copyright 2022 Olaf Wintermann
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a 
5  * copy of this software and associated documentation files (the "Software"), 
6  * to deal in the Software without restriction, including without limitation 
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense, 
8  * and/or sell copies of the Software, and to permit persons to whom the 
9  * Software is furnished to do so, subject to the following conditions:
10  * 
11  * The above copyright notice and this permission notice shall be included in 
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
17  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
20  * DEALINGS IN THE SOFTWARE.
21  */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <locale.h>
27 #include <time.h>
28 #include <inttypes.h>
29 #include <sys/stat.h>
30
31 #include "window.h"
32 #include "main.h"
33 #include "settings.h"
34
35 #include <ucx/buffer.h>
36 #include <ucx/utils.h>
37
38 static XtAppContext app;
39 static Display *display;
40 static Widget toplevel_window;
41
42 static char *open_file_arg;
43
44 static int event_pipe[2];
45
46 static String fallback[] = {
47         "*renderTable: rt",
48         "*rt*fontType: FONT_IS_XFT",
49         "*rt*fontName: Sans",
50         "*rt*fontSize: 9",
51         
52         "*pbbutton.shadowThickness: 1",
53         "*pbbutton.highlightThickness: 1",
54         
55         "*XmText.baseTranslations: #override\\n" \
56                                 "Ctrl~Alt~Meta<KeyPress>v: paste-clipboard()\\n" \
57                                 "Ctrl~Alt~Meta<KeyPress>c: copy-clipboard()\\n" \
58                                 "Ctrl~Alt~Meta<KeyPress>x: cut-clipboard()\\n" \
59                                 "Ctrl~Alt~Meta<KeyPress>u: delete-to-start-of-line()\\n",
60         "*XmTextField.baseTranslations: #override\\n" \
61                                 "Ctrl~Alt~Meta<KeyPress>v: paste-clipboard()\\n" \
62                                 "Ctrl~Alt~Meta<KeyPress>c: copy-clipboard()\\n" \
63                                 "Ctrl~Alt~Meta<KeyPress>x: cut-clipboard()\\n" \
64                                 "Ctrl~Alt~Meta<KeyPress>u: delete-to-start-of-line()\\n",
65         NULL
66 };
67
68 static String langProc(Display *dp, String xnl, XtPointer closure) {
69     setlocale(LC_ALL, xnl);
70     setlocale(LC_NUMERIC, "C");
71     return setlocale(LC_ALL, NULL);
72 }
73
74 typedef struct EventLoopCB {
75     XtWorkProc proc;
76     XtPointer data;
77 } EventLoopCB;
78
79 static void input_proc(XtPointer data, int *source, XtInputId *iid) {
80     EventLoopCB cb[16];
81     ssize_t r = read(event_pipe[0], cb, sizeof(EventLoopCB)*16);
82     size_t n = r / sizeof(EventLoopCB);
83     for(int i=0;i<n;i++) {
84         cb[i].proc(cb[i].data);
85     }
86 }
87
88 int main(int argc, char** argv) {  
89     // disable stdout buffering, because the netbeans's internal terminal
90     // has a bug on freebsd and doesn't flush the output after a newline
91     setvbuf(stdout, NULL, _IONBF, 0);
92     
93     // init event pipe for xt event loop
94     if(pipe(event_pipe)) {
95         perror("pipe");
96         return 2;
97     }
98      
99     // initialize toolkit
100     XtToolkitInitialize();
101     XtSetLanguageProc(NULL, langProc, NULL);
102     app = XtCreateApplicationContext();
103     XtAppSetFallbackResources(app, fallback);
104        
105     display =  XtOpenDisplay(app, NULL, APP_NAME, APP_CLASS, NULL, 0, &argc, argv);
106     
107     if(argc > 1) {
108         struct stat s;
109         if(stat(argv[1], &s)) {
110             fprintf(stderr, "Cannot open file: %s\n", argv[1]);
111             perror("");
112             return 1;
113         }
114         open_file_arg = argv[1];
115     }
116     
117     XtAppAddInput(
118             app,
119             event_pipe[0],
120             (XtPointer)XtInputReadMask,
121             input_proc,
122             NULL);
123     
124     // load settings
125     if(load_config()) {
126         return 1;
127     }
128    
129     MainWindow *window = WindowCreate(display);
130     toplevel_window = window->window;
131     
132     // random numbers used for creating tmp dirs and for random playback
133     srand(time(NULL));
134     
135     WindowShow(window);
136     AppMainLoop(app);
137     
138     return 0;
139 }
140
141 XtAppContext* GetAppContext(void) {
142     return &app;
143 }
144
145 void ApplicationExit(void) {
146     XtAppSetExitFlag(app);
147 }
148
149 void AppExecProc(XtWorkProc proc, XtPointer data) {
150     EventLoopCB cb;
151     cb.proc = proc;
152     cb.data = data;
153     write(event_pipe[1], &cb, sizeof(cb));
154 }
155
156 char* GetOpenFileArg(void) {
157     return open_file_arg;
158 }
159
160 void CleanOpenFileArg(void) {
161     open_file_arg = NULL;
162 }
163
164 static Window app_player_window = 0;
165
166 void SetPlayerWindow(Window w) {
167     app_player_window = w;
168 }
169
170 /*
171  * Extended Xt main loop, that also handles external window events
172  */
173 void AppMainLoop(XtAppContext app) {
174     while(!XtAppGetExitFlag(app)) {
175         XEvent event;
176         XtAppNextEvent(app, &event);
177         
178         if(app_player_window != 0 && event.xany.window == app_player_window) {
179             WindowHandlePlayerEvent(GetMainWindow(), &event);
180         } else {
181             XtDispatchEvent(&event);
182         }
183     }
184 }