* GNT - The GLib Ncurses Toolkit * GNT is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA #if (defined(__APPLE__) || defined(__unix__)) && !defined(__FreeBSD__) && !defined(__OpenBSD__) #define _XOPEN_SOURCE_EXTENDED #define GNT_LOG_DOMAIN "Main" #include "gntclipboard.h" * Notes: Interesting functions to look at: * scr_dump, scr_init, scr_restore: for workspaces * Need to wattrset for colors to use with PDCurses. static GIOChannel *channel = NULL; static guint channel_read_callback = 0; static guint channel_error_callback = 0; static gboolean ascii_only; static gboolean mouse_enabled; static void setup_io(void); static gboolean refresh_screen(void); static GntClipboard *clipboard; int gnt_need_conversation_to_locale; #define HOLDING_ESCAPE (escape_stuff.timer != 0) escape_timeout(gpointer data) gnt_wm_process_input(wm, "\033"); * - bring a window on top if you click on its taskbar * - click on the top-bar of the active window and drag+drop to move a window * - click on a window to bring it to focus * - allow scrolling in tree/textview on wheel-scroll event * - click to activate button or select a row in tree * - have a little [X] on the windows, and clicking it will close that window. detect_mouse_action(const char *buffer) static GntWidget *remember = NULL; GntWidget *widget = NULL; if (!wm->cws->ordered || buffer[0] != 27) while ((p = panel_below(p)) != NULL) { const GntNode *node = panel_userptr(p); if (x >= wid->priv.x && x < wid->priv.x + wid->priv.width) { if (y >= wid->priv.y && y < wid->priv.y + wid->priv.height) { if (strncmp(buffer, "[M ", 3) == 0) { /* Bring the window you clicked on to front */ /* If you click on the topbar, then you can drag to move the window */ event = GNT_LEFT_MOUSE_DOWN; } else if (strncmp(buffer, "[M\"", 3) == 0) { event = GNT_RIGHT_MOUSE_DOWN; } else if (strncmp(buffer, "[M!", 3) == 0) { event = GNT_MIDDLE_MOUSE_DOWN; } else if (strncmp(buffer, "[M`", 3) == 0) { event = GNT_MOUSE_SCROLL_UP; } else if (strncmp(buffer, "[Ma", 3) == 0) { event = GNT_MOUSE_SCROLL_DOWN; } else if (strncmp(buffer, "[M#", 3) == 0) { if (widget && gnt_wm_process_click(wm, event, x, y, widget)) if (event == GNT_LEFT_MOUSE_DOWN && widget && widget != wm->_list.window && !GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_TRANSIENT)) { if (widget != wm->cws->ordered->data) { gnt_wm_raise_window(wm, widget); if (y == widget->priv.y) { offset = x - widget->priv.x; } else if (event == GNT_MOUSE_UP) { if (button == MOUSE_NONE && y == getmaxy(stdscr) - 1) { /* Clicked on the taskbar */ int n = g_list_length(wm->cws->list); int width = getmaxx(stdscr) / n; gnt_bindable_perform_action_named(GNT_BINDABLE(wm), "switch-window-n", x/width, NULL); } else if (button == MOUSE_LEFT && remember) { gnt_screen_move_widget(remember, x, y); gnt_widget_clicked(widget, event, x, y); io_invoke_error(GIOChannel *source, GIOCondition cond, gpointer data) int id = GPOINTER_TO_INT(data); g_io_channel_unref(source); io_invoke(GIOChannel *source, GIOCondition cond, gpointer null) if (wm->mode == GNT_KP_MODE_WAIT_ON_CHILD) rd = read(STDIN_FILENO, keys + HOLDING_ESCAPE, sizeof(keys) - 1 - HOLDING_ESCAPE); int ch = getch(); /* This should return ERR, but let's see what it really returns */ printf("ERROR: %s\n", strerror(errno)); printf("File descriptor is: %d\n\nGIOChannel is: %p\ngetch() = %d\n", STDIN_FILENO, source, ch); g_source_remove(escape_stuff.timer); gnt_wm_set_event_stack(wm, TRUE); cvrt = g_locale_to_utf8(keys, rd, (gsize*)&rd, NULL, NULL); if (mouse_enabled && detect_mouse_action(k)) /* I am not sure what's happening here. If this actually does something, * then this needs to go in gnt_keys_refine. */ if (*k < 0) { /* Alt not sending ESC* */ if (k[0] == '\033' && rd == 1) { escape_stuff.timer = g_timeout_add(250, escape_timeout, NULL); p = MAX(1, gnt_keys_find_combination(k)); gnt_wm_process_input(wm, k); /* XXX: */ gnt_wm_set_event_stack(wm, FALSE); channel = g_io_channel_unix_new(STDIN_FILENO); g_io_channel_set_close_on_unref(channel, TRUE); g_io_channel_set_encoding(channel, NULL, NULL); g_io_channel_set_buffered(channel, FALSE); g_io_channel_set_flags(channel, G_IO_FLAG_NONBLOCK, NULL ); channel_read_callback = result = g_io_add_watch_full(channel, G_PRIORITY_HIGH, (G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI), channel_error_callback = g_io_add_watch_full(channel, G_PRIORITY_HIGH, io_invoke_error, GINT_TO_POINTER(result), NULL); g_io_channel_unref(channel); /* Apparently this caused crashes for some people. But irssi does this, so I am going to assume the crashes were caused by some other stuff. */ gnt_warning("setting up IO (%d)", channel_read_callback); gnt_bindable_perform_action_named(GNT_BINDABLE(wm), "refresh-screen", NULL); pid = waitpid(-1, &status, WNOHANG); } while (pid != 0 && pid != (pid_t)-1); if ((pid == (pid_t) - 1) && (errno != ECHILD)) { g_snprintf(errmsg, BUFSIZ, "Warning: waitpid() returned %d", pid); exit_confirmed(gpointer null) gnt_bindable_perform_action_named(GNT_BINDABLE(wm), "wm-quit", NULL); exit_win_close(GntWidget *w, GntWidget **win) static GntWidget *win = NULL; GntWidget *bbox, *button; gnt_widget_hide(GNT_WIDGET(wm->menu)); wm->menu = wm->menu->parentmenu; win = gnt_vwindow_new(FALSE); gnt_box_add_widget(GNT_BOX(win), gnt_label_new("Are you sure you want to quit?")); gnt_box_set_title(GNT_BOX(win), "Quit?"); gnt_box_set_alignment(GNT_BOX(win), GNT_ALIGN_MID); g_signal_connect(G_OBJECT(win), "destroy", G_CALLBACK(exit_win_close), &win); bbox = gnt_hbox_new(FALSE); gnt_box_add_widget(GNT_BOX(win), bbox); button = gnt_button_new("Quit"); g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(exit_confirmed), NULL); gnt_box_add_widget(GNT_BOX(bbox), button); button = gnt_button_new("Cancel"); g_signal_connect_swapped(G_OBJECT(button), "activate", G_CALLBACK(gnt_widget_destroy), win); gnt_box_add_widget(GNT_BOX(bbox), button); gnt_wm_raise_window(wm, win); static void (*org_winch_handler)(int); g_idle_add((GSourceFunc)refresh_screen, NULL); signal(SIGWINCH, sighandler); signal(SIGCHLD, sighandler); signal(SIGINT, sighandler); const char *name = gnt_style_get(GNT_STYLE_WM); handle = g_module_open(name, G_MODULE_BIND_LAZY); gboolean (*init)(GntWM **); if (g_module_symbol(handle, "gntwm_init", (gpointer)&init)) { wm = g_object_new(GNT_TYPE_WM, NULL); locale = setlocale(LC_ALL, ""); if (locale && (strstr(locale, "UTF") || strstr(locale, "utf"))) { gnt_need_conversation_to_locale = TRUE; filename = g_build_filename(g_get_home_dir(), ".gntrc", NULL); gnt_style_read_configure_file(filename); wbkgdset(stdscr, '\0' | gnt_color_pair(GNT_COLOR_NORMAL)); if ((mouse_enabled = gnt_style_get_bool(GNT_STYLE_MOUSE, FALSE))) mousemask(ALL_MOUSE_EVENTS | REPORT_MOUSE_POSITION, NULL); wbkgdset(stdscr, '\0' | gnt_color_pair(GNT_COLOR_NORMAL)); org_winch_handler = signal(SIGWINCH, sighandler); signal(SIGCHLD, sighandler); signal(SIGINT, sighandler); signal(SIGPIPE, SIG_IGN); #if !GLIB_CHECK_VERSION(2, 36, 0) /* GLib type system is automaticaly initialized since 2.36. */ clipboard = g_object_new(GNT_TYPE_CLIPBOARD, NULL); wm->loop = g_main_loop_new(NULL, FALSE); g_main_loop_run(wm->loop); /********************************* * Stuff for 'window management' * *********************************/ void gnt_window_present(GntWidget *window) gnt_wm_raise_window(wm, window); gnt_widget_set_urgent(window); void gnt_screen_occupy(GntWidget *widget) gnt_wm_new_window(wm, widget); void gnt_screen_release(GntWidget *widget) gnt_wm_window_close(wm, widget); void gnt_screen_update(GntWidget *widget) gnt_wm_update_window(wm, widget); gboolean gnt_widget_has_focus(GntWidget *widget) if (widget == wm->_list.window) if (wm->cws->ordered && wm->cws->ordered->data == widget) { if (GNT_IS_BOX(widget) && (GNT_BOX(widget)->active == w || widget == w)) void gnt_widget_set_urgent(GntWidget *widget) if (wm->cws->ordered && wm->cws->ordered->data == widget) GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_URGENT); gnt_wm_update_window(wm, widget); /* Prevent io_invoke() from being called after wm is destroyed */ g_source_remove(channel_error_callback); g_source_remove(channel_read_callback); channel_error_callback = 0; channel_read_callback = 0; g_object_unref(G_OBJECT(wm)); gboolean gnt_ascii_only() void gnt_screen_resize_widget(GntWidget *widget, int width, int height) gnt_wm_resize_window(wm, widget, width, height); void gnt_screen_move_widget(GntWidget *widget, int x, int y) gnt_wm_move_window(wm, widget, x, y); void gnt_screen_rename_widget(GntWidget *widget, const char *text) gnt_box_set_title(GNT_BOX(widget), text); gnt_wm_update_window(wm, widget); void gnt_register_action(const char *label, void (*callback)(void)) GntAction *action = g_new0(GntAction, 1); action->label = g_strdup(label); action->callback = callback; wm->acts = g_list_append(wm->acts, action); reset_menu(GntWidget *widget, gpointer null) gboolean gnt_screen_menu_show(gpointer newmenu) /* For now, if a menu is being displayed, then another menu GNT_WIDGET_UNSET_FLAGS(GNT_WIDGET(wm->menu), GNT_WIDGET_INVISIBLE); gnt_widget_draw(GNT_WIDGET(wm->menu)); g_signal_connect(G_OBJECT(wm->menu), "hide", G_CALLBACK(reset_menu), NULL); g_signal_connect(G_OBJECT(wm->menu), "destroy", G_CALLBACK(reset_menu), NULL); void gnt_set_clipboard_string(const gchar *string) gnt_clipboard_set_string(clipboard, string); GntClipboard *gnt_get_clipboard() gchar *gnt_get_clipboard_string() return gnt_clipboard_get_string(clipboard); void (*callback)(int status, gpointer data); reap_child(GPid pid, gint status, gpointer data) cp->callback(status, cp->data); wm->mode = GNT_KP_MODE_NORMAL; gboolean gnt_giveup_console(const char *wd, char **argv, char **envp, gint *stin, gint *stout, gint *sterr, void (*callback)(int status, gpointer data), gpointer data) if (!g_spawn_async_with_pipes(wd, argv, envp, G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD, (GSpawnChildSetupFunc)endwin, NULL, &pid, stin, stout, sterr, NULL)) cp = g_new0(ChildProcess, 1); g_source_remove(channel_read_callback); wm->mode = GNT_KP_MODE_WAIT_ON_CHILD; g_child_watch_add(pid, reap_child, cp); gboolean gnt_is_refugee() return (wm && wm->mode == GNT_KP_MODE_WAIT_ON_CHILD); const char *C_(const char *x) if (gnt_need_conversation_to_locale) { c = g_locale_from_utf8(x, -1, NULL, NULL, &error); if (c == NULL || error) { gnt_warning("Error: %s\n", error ? error->message : "(unknown)");