diff finch/libgnt/gntmain.c @ 15817:0e3a8505ebbe

renamed gaim-text to finch
author Sean Egan <seanegan@gmail.com>
date Sun, 18 Mar 2007 19:38:15 +0000
parents
children 82b6fdd899a9
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/finch/libgnt/gntmain.c	Sun Mar 18 19:38:15 2007 +0000
@@ -0,0 +1,535 @@
+#define _GNU_SOURCE
+#if defined(__APPLE__)
+#define _XOPEN_SOURCE_EXTENDED
+#endif
+
+#include "config.h"
+
+#include <gmodule.h>
+
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "gnt.h"
+#include "gntbox.h"
+#include "gntcolors.h"
+#include "gntclipboard.h"
+#include "gntkeys.h"
+#include "gntmenu.h"
+#include "gntstyle.h"
+#include "gnttree.h"
+#include "gntutils.h"
+#include "gntwm.h"
+
+#include <panel.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <locale.h>
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.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 gboolean ascii_only;
+static gboolean mouse_enabled;
+
+static void setup_io(void);
+
+static gboolean refresh_screen();
+
+GntWM *wm;
+static GntClipboard *clipboard;
+
+#define HOLDING_ESCAPE  (escape_stuff.timer != 0)
+
+static struct {
+	int timer;
+} escape_stuff;
+
+static gboolean
+escape_timeout(gpointer data)
+{
+	gnt_wm_process_input(wm, "\033");
+	escape_stuff.timer = 0;
+	return FALSE;
+}
+
+/**
+ * Mouse support:
+ *  - 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
+ *  wishlist:
+ *   - have a little [X] on the windows, and clicking it will close that window.
+ */
+static gboolean
+detect_mouse_action(const char *buffer)
+{
+	int x, y;
+	static enum {
+		MOUSE_NONE,
+		MOUSE_LEFT,
+		MOUSE_RIGHT,
+		MOUSE_MIDDLE
+	} button = MOUSE_NONE;
+	static GntWidget *remember = NULL;
+	static int offset = 0;
+	GntMouseEvent event;
+	GntWidget *widget = NULL;
+	PANEL *p = NULL;
+
+	if (!wm->ordered || buffer[0] != 27)
+		return FALSE;
+	
+	buffer++;
+	if (strlen(buffer) < 5)
+		return FALSE;
+
+	x = buffer[3];
+	y = buffer[4];
+	if (x < 0)	x += 256;
+	if (y < 0)	y += 256;
+	x -= 33;
+	y -= 33;
+
+	while ((p = panel_below(p)) != NULL) {
+		const GntNode *node = panel_userptr(p);
+		GntWidget *wid;
+		if (!node)
+			continue;
+		wid = node->me;
+		if (x >= wid->priv.x && x < wid->priv.x + wid->priv.width) {
+			if (y >= wid->priv.y && y < wid->priv.y + wid->priv.height) {
+				widget = wid;
+				break;
+			}
+		}
+	}
+
+	if (strncmp(buffer, "[M ", 3) == 0) {
+		/* left button down */
+		/* 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) {
+		/* right button down */
+		event = GNT_RIGHT_MOUSE_DOWN;
+	} else if (strncmp(buffer, "[M!", 3) == 0) {
+		/* middle button down */
+		event = GNT_MIDDLE_MOUSE_DOWN;
+	} else if (strncmp(buffer, "[M`", 3) == 0) {
+		/* wheel up*/
+		event = GNT_MOUSE_SCROLL_UP;
+	} else if (strncmp(buffer, "[Ma", 3) == 0) {
+		/* wheel down */
+		event = GNT_MOUSE_SCROLL_DOWN;
+	} else if (strncmp(buffer, "[M#", 3) == 0) {
+		/* button up */
+		event = GNT_MOUSE_UP;
+	} else
+		return FALSE;
+	
+	if (gnt_wm_process_click(wm, event, x, y, widget))
+		return TRUE;
+	
+	if (event == GNT_LEFT_MOUSE_DOWN && widget && widget != wm->_list.window &&
+			!GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_TRANSIENT)) {
+		if (widget != wm->ordered->data) {
+			gnt_wm_raise_window(wm, widget);
+		}
+		if (y == widget->priv.y) {
+			offset = x - widget->priv.x;
+			remember = widget;
+			button = MOUSE_LEFT;
+		}
+	} else if (event == GNT_MOUSE_UP) {
+		if (button == MOUSE_NONE && y == getmaxy(stdscr) - 1) {
+			/* Clicked on the taskbar */
+			int n = g_list_length(wm->list);
+			if (n) {
+				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) {
+			x -= offset;
+			if (x < 0)	x = 0;
+			if (y < 0)	y = 0;
+			gnt_screen_move_widget(remember, x, y);
+		}
+		button = MOUSE_NONE;
+		remember = NULL;
+		offset = 0;
+	}
+
+	gnt_widget_clicked(widget, event, x, y);
+	return TRUE;
+}
+
+static gboolean
+io_invoke_error(GIOChannel *source, GIOCondition cond, gpointer data)
+{
+	int id = GPOINTER_TO_INT(data);
+	g_source_remove(id);
+	g_io_channel_unref(source);
+
+	channel = NULL;
+	setup_io();
+	return TRUE;
+}
+
+static gboolean
+io_invoke(GIOChannel *source, GIOCondition cond, gpointer null)
+{
+	char keys[256];
+	int rd = read(STDIN_FILENO, keys + HOLDING_ESCAPE, sizeof(keys) - 1 - HOLDING_ESCAPE);
+	char *k;
+	if (rd < 0)
+	{
+		int ch = getch(); /* This should return ERR, but let's see what it really returns */
+		endwin();
+		printf("ERROR: %s\n", strerror(errno));
+		printf("File descriptor is: %d\n\nGIOChannel is: %p\ngetch() = %d\n", STDIN_FILENO, source, ch);
+		raise(SIGABRT);
+	}
+	else if (rd == 0)
+	{
+		endwin();
+		printf("EOF\n");
+		raise(SIGABRT);
+	}
+
+	rd += HOLDING_ESCAPE;
+	keys[rd] = 0;
+	if (mouse_enabled && detect_mouse_action(keys))
+		return TRUE;
+
+	if (HOLDING_ESCAPE)
+		keys[0] = '\033';
+	k = keys;
+	while (rd) {
+		char back;
+		int p;
+
+		if (k[0] == '\033' && rd == 1) {
+			if (escape_stuff.timer) {
+				gnt_wm_process_input(wm, "\033\033");
+				g_source_remove(escape_stuff.timer);
+				escape_stuff.timer = 0;
+				break;
+			}
+			escape_stuff.timer = g_timeout_add(250, escape_timeout, NULL);
+			break;
+		}
+
+		gnt_keys_refine(k);
+		p = MAX(1, gnt_keys_find_combination(k));
+		back = k[p];
+		k[p] = '\0';
+		gnt_wm_process_input(wm, k);     /* XXX: */
+		k[p] = back;
+		rd -= p;
+		k += p;
+	}
+
+	return TRUE;
+}
+
+static void
+setup_io()
+{
+	int result;
+	channel = g_io_channel_unix_new(STDIN_FILENO);
+	g_io_channel_set_close_on_unref(channel, TRUE);
+
+#if 0
+	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 );
+#endif
+
+	result = g_io_add_watch_full(channel,  G_PRIORITY_HIGH,
+					(G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI),
+					io_invoke, NULL, NULL);
+	
+	g_io_add_watch_full(channel,  G_PRIORITY_HIGH,
+					(G_IO_NVAL),
+					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. */
+
+	g_printerr("gntmain: setting up IO\n");
+}
+
+static gboolean
+refresh_screen()
+{
+	gnt_bindable_perform_action_named(GNT_BINDABLE(wm), "refresh-screen", NULL);
+	return FALSE;
+}
+
+/* Xerox */
+static void
+clean_pid(void)
+{
+	int status;
+	pid_t pid;
+
+	do {
+		pid = waitpid(-1, &status, WNOHANG);
+	} while (pid != 0 && pid != (pid_t)-1);
+
+	if ((pid == (pid_t) - 1) && (errno != ECHILD)) {
+		char errmsg[BUFSIZ];
+		g_snprintf(errmsg, BUFSIZ, "Warning: waitpid() returned %d", pid);
+		perror(errmsg);
+	}
+}
+
+static void
+sighandler(int sig)
+{
+	switch (sig) {
+#ifdef SIGWINCH
+	case SIGWINCH:
+		werase(stdscr);
+		wrefresh(stdscr);
+		g_idle_add(refresh_screen, NULL);
+		signal(SIGWINCH, sighandler);
+		break;
+#endif
+	case SIGCHLD:
+		clean_pid();
+		signal(SIGCHLD, sighandler);
+		break;
+	}
+}
+
+static void
+init_wm()
+{
+	const char *name = gnt_style_get(GNT_STYLE_WM);
+	gpointer handle;
+	
+	if (name && *name) {
+		handle = g_module_open(name, G_MODULE_BIND_LAZY);
+		if (handle) {
+			gboolean (*init)(GntWM **);
+			if (g_module_symbol(handle, "gntwm_init", (gpointer)&init)) {
+				init(&wm);
+			}
+		}
+	}
+	if (wm == NULL)
+		wm = g_object_new(GNT_TYPE_WM, NULL);
+}
+
+void gnt_init()
+{
+	char *filename;
+	const char *locale;
+
+	if (channel)
+		return;
+	
+	locale = setlocale(LC_ALL, "");
+
+	setup_io();
+
+	if (locale && (strstr(locale, "UTF") || strstr(locale, "utf")))
+		ascii_only = FALSE;
+	else
+		ascii_only = TRUE;
+
+	initscr();
+	typeahead(-1);
+	noecho();
+	curs_set(0);
+
+	gnt_init_keys();
+	gnt_init_styles();
+
+	filename = g_build_filename(g_get_home_dir(), ".gntrc", NULL);
+	gnt_style_read_configure_file(filename);
+	g_free(filename);
+
+	gnt_init_colors();
+
+	wbkgdset(stdscr, '\0' | COLOR_PAIR(GNT_COLOR_NORMAL));
+	refresh();
+
+#ifdef ALL_MOUSE_EVENTS
+	if ((mouse_enabled = gnt_style_get_bool(GNT_STYLE_MOUSE, FALSE)))
+		mousemask(ALL_MOUSE_EVENTS | REPORT_MOUSE_POSITION, NULL);
+#endif
+
+	wbkgdset(stdscr, '\0' | COLOR_PAIR(GNT_COLOR_NORMAL));
+	werase(stdscr);
+	wrefresh(stdscr);
+
+#ifdef SIGWINCH
+	signal(SIGWINCH, sighandler);
+#endif
+	signal(SIGCHLD, sighandler);
+	signal(SIGPIPE, SIG_IGN);
+
+	g_type_init();
+
+	init_wm();
+
+	clipboard = g_object_new(GNT_TYPE_CLIPBOARD, NULL);
+}
+
+void gnt_main()
+{
+	wm->loop = g_main_loop_new(NULL, FALSE);
+	g_main_loop_run(wm->loop);
+}
+
+/*********************************
+ * Stuff for 'window management' *
+ *********************************/
+
+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)
+{
+	GntWidget *w;
+	if (!widget)
+		return FALSE;
+	
+	if (GNT_IS_MENU(widget))
+		return TRUE;
+
+	w = widget;
+
+	while (widget->parent)
+		widget = widget->parent;
+
+	if (widget == wm->_list.window)
+		return TRUE;
+	if (wm->ordered && wm->ordered->data == widget) {
+		if (GNT_IS_BOX(widget) &&
+				(GNT_BOX(widget)->active == w || widget == w))
+			return TRUE;
+	}
+	return FALSE;
+}
+
+void gnt_widget_set_urgent(GntWidget *widget)
+{
+	while (widget->parent)
+		widget = widget->parent;
+
+	if (wm->ordered && wm->ordered->data == widget)
+		return;
+
+	GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_URGENT);
+
+	gnt_wm_update_window(wm, widget);
+}
+
+void gnt_quit()
+{
+	g_hash_table_destroy(wm->nodes); /* XXX: */
+	update_panels();
+	doupdate();
+	gnt_uninit_colors();
+	gnt_uninit_styles();
+	endwin();
+}
+
+gboolean gnt_ascii_only()
+{
+	return 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_widget_draw(widget);
+	gnt_wm_update_window(wm, widget);
+}
+
+void gnt_register_action(const char *label, void (*callback)())
+{
+	GntAction *action = g_new0(GntAction, 1);
+	action->label = g_strdup(label);
+	action->callback = callback;
+
+	wm->acts = g_list_append(wm->acts, action);
+}
+
+static void
+reset_menu(GntWidget *widget, gpointer null)
+{
+	wm->menu = NULL;
+}
+
+gboolean gnt_screen_menu_show(gpointer newmenu)
+{
+	if (wm->menu) {
+		/* For now, if a menu is being displayed, then another menu
+		 * can NOT take over. */
+		return FALSE;
+	}
+
+	wm->menu = newmenu;
+	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);
+
+	return TRUE;
+}
+
+void gnt_set_clipboard_string(gchar *string)
+{
+	gnt_clipboard_set_string(clipboard, string);
+}
+
+GntClipboard *gnt_get_clipboard()
+{
+	return clipboard;
+}
+gchar *gnt_get_clipboard_string()
+{
+	return gnt_clipboard_get_string(clipboard);
+}