static Display *display;
static Widget toplevel_window;
+static int event_pipe[2];
+
static String fallback[] = {
"*renderTable: rt",
"*rt*fontType: FONT_IS_XFT",
return setlocale(LC_ALL, NULL);
}
+typedef struct EventLoopCB {
+ XtWorkProc proc;
+ XtPointer data;
+} EventLoopCB;
+
+static void input_proc(XtPointer data, int *source, XtInputId *iid) {
+ EventLoopCB cb[16];
+ ssize_t r = read(event_pipe[0], cb, sizeof(EventLoopCB)*16);
+ size_t n = r / sizeof(EventLoopCB);
+ for(int i=0;i<n;i++) {
+ cb[i].proc(cb[i].data);
+ }
+}
+
int main(int argc, char** argv) {
// disable stdout buffering, because the netbeans's internal terminal
// has a bug on freebsd and doesn't flush the output after a newline
setvbuf(stdout, NULL, _IONBF, 0);
+
+ // init event pipe for xt event loop
+ if(pipe(event_pipe)) {
+ perror("pipe");
+ return 2;
+ }
// initialize toolkit
XtToolkitInitialize();
display = XtOpenDisplay(app, NULL, APP_NAME, APP_CLASS, NULL, 0, &argc, argv);
+ XtAppAddInput(
+ app,
+ event_pipe[0],
+ (XtPointer)XtInputReadMask,
+ input_proc,
+ NULL);
+
// load settings
if(load_settings()) {
return 1;
XtAppSetExitFlag(app);
}
-void AppAddTimeOut(unsigned long interval, XtTimerCallbackProc proc, XtPointer data) {
- XtAppAddTimeOut(app, interval, proc, data);
-
- if(!toplevel_window) return;
-
- // send a dummy X11 event, because the event loop may be waiting
- // and the timeout proc is only called when an event is processed
- XClientMessageEvent event;
- memset(&event, 0, sizeof(XClientMessageEvent));
- event.type = ClientMessage;
- event.window = XtWindow(toplevel_window);
- event.format = 32;
- XSendEvent(display, XtWindow(toplevel_window), 0, 0, (XEvent*)&event);
- XFlush(display);
+void AppExecProc(XtWorkProc proc, XtPointer data) {
+ EventLoopCB cb;
+ cb.proc = proc;
+ cb.data = data;
+ write(event_pipe[1], &cb, sizeof(cb));
}
void ApplicationExit(void);
-void AppAddTimeOut(unsigned long interval, XtTimerCallbackProc proc, XtPointer data);
+void AppExecProc(XtWorkProc proc, XtPointer data);
#ifdef __cplusplus
static void handle_json_rpc_msg(Player *player, JSONValue *v) {
if(v->type != JSON_OBJECT) return;
-
+
JSONValue *request_id_v = json_obj_get(&v->value.object, "request_id");
JSONValue *event = NULL;
if(request_id_v && request_id_v->type == JSON_STRING) {
handle_json_rpc_event(player, v, event);
}
- json_print(v, NULL, 0);
+ //json_print(v, NULL, 0);
fflush(stdout);
}
-static void player_widget_set_size(XtPointer data, XtIntervalId *id) {
+static Boolean player_widget_set_size(XtPointer data) {
Player *player = data;
MainWindow *win = GetMainWindow();
Dimension new_width = player->width + win_width - player_width;
Dimension new_height = player->height + win_height - player_height;
+ // set window size
XtVaSetValues(win->window, XmNwidth, new_width, XmNheight, new_height, NULL);
+ // set window aspect ratio
+ XSizeHints hints;
+ hints.flags = PAspect;
+ hints.min_aspect.x = new_width;
+ hints.min_aspect.y = new_height;
+ hints.max_aspect.x = new_width;
+ hints.max_aspect.y = new_height;
+ XSetWMNormalHints(XtDisplay(win->window), XtWindow(win->window), &hints);
+
+ return 0;
}
player->height = height;
}
if(player->width > 0 && player->height > 0) {
- AppAddTimeOut(0, player_widget_set_size, player);
+ AppExecProc(player_widget_set_size, player);
}
}
PlayerEOF(p);
}
}
- } else if(!json_strcmp(event, "playback-restart")) {
+ } else if(!p->isstarted && !json_strcmp(event, "playback-restart")) {
char *cmd = "{ \"command\": [\"observe_property\", 1, \"playback-time\"] }\n"
"{ \"command\": [\"observe_property\", 1, \"eof-reached\"] }\n"
"{ \"command\": [\"get_property\", \"width\"], request_id=\"" REQ_ID_WIDTH "\" }\n"
"{ \"command\": [\"get_property\", \"height\"], request_id=\"" REQ_ID_HEIGHT "\" }\n"
"{ \"command\": [\"set_property\", \"keep-open\", true] }\n";
write(p->ipc, cmd, strlen(cmd));
+ p->isstarted = TRUE;
}
}
return NULL;
}
-static void finish_bin_search(XtPointer data, XtIntervalId *id) {
+static Boolean finish_bin_search(XtPointer data) {
PlayerInfo *playerInfo = data;
ucx_map_cstr_put(uwp_settings, UWP_PLAYER_BIN, playerInfo->bin);
ucx_map_cstr_put(uwp_settings, UWP_PLAYER_TYPE, playerInfo->type);
free(playerInfo);
+ return 0;
}
static void* player_bin_search_thread(void *data) {
PlayerInfo *playerInfo = malloc(sizeof(PlayerInfo));
playerInfo->bin = strdup(bin);
playerInfo->type = strdup("mpv");
- AppAddTimeOut(0, finish_bin_search, playerInfo);
+ AppExecProc(finish_bin_search, playerInfo);
ucx_buffer_free(buf);
return NULL;
PlayerInfo *playerInfo = malloc(sizeof(PlayerInfo));
playerInfo->bin = strdup(bin);
playerInfo->type = strdup("mplayer");
- AppAddTimeOut(0, finish_bin_search, playerInfo);
+ AppExecProc(finish_bin_search, playerInfo);
}
}
}
}
+static void resizeEH(Widget widget, XtPointer data, XEvent *event, Boolean *dispatch) {
+ WindowAdjustAspectRatio(data);
+}
+
MainWindow* WindowCreate(Display *display) {
Arg args[32];
int n;
args,
n);
-
+ // close handler
Atom wm_delete_window;
wm_delete_window = XmInternAtom(
display,
window_close_handler,
window);
-
+ // resize handler
+ XtAddEventHandler(window->window, StructureNotifyMask, False, resizeEH, window);
+
n = 0;
XtSetArg(args[n], XmNwidth, 360); n++;
XtSetArg(args[n], XmNheight, 220); n++;
XtSetArg(args[n], XmNbackground, BlackPixelOfScreen(XtScreen(window->window))); n++;
window->player_widget = XmCreateDrawingArea(container, "player", args, n);
XtManageChild(window->player_widget);
+ XmProcessTraversal(window->player_widget, XmTRAVERSE_CURRENT);
// get F keycode
keycodeF = XKeysymToKeycode(XtDisplay(window->window), XStringToKeysym("F"));
}
}
+
+void WindowAdjustAspectRatio(MainWindow *win) {
+ if(!win->player) return;
+ if(!win->player->isactive || win->player->width <= 0 || win->player->height <= 0) return;
+
+ // we have a running player width video
+ // adjust window aspect ratio (the window aspect ratio is different from
+ // the video, because of window decoration, menubar and other extra controls)
+
+ Dimension win_width, win_height;
+ XtVaGetValues(win->window, XmNwidth, &win_width, XmNheight, &win_height, NULL);
+ Dimension player_width, player_height;
+ XtVaGetValues(win->player_widget, XmNwidth, &player_width, XmNheight, &player_height, NULL);
+
+ double r = (double)win->player->width / (double)win->player->height;
+ double p_width = player_width;
+ double p_height = p_width / r;
+
+ Dimension new_width = p_width + win_width - player_width;
+ Dimension new_height = p_height + win_height - player_height;
+
+ XSizeHints hints;
+ hints.flags = PAspect;
+ hints.min_aspect.x = new_width;
+ hints.min_aspect.y = new_height;
+ hints.max_aspect.x = new_width;
+ hints.max_aspect.y = new_height;
+ XSetWMNormalHints(XtDisplay(win->window), XtWindow(win->window), &hints);
+}
int ipc;
int status;
bool isactive;
+ bool isstarted;
double playback_time;
int width;
void WindowMenubarSetVisible(MainWindow *win, bool visible);
+void WindowAdjustAspectRatio(MainWindow *win);
+
#ifdef __cplusplus
}
#endif