⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gntwm.c

📁 Linux下的多协议即时通讯程序源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
#define _GNU_SOURCE#if defined(__APPLE__)#define _XOPEN_SOURCE_EXTENDED#endif#include "config.h"#include <ctype.h>#include <stdlib.h>#include <string.h>#include <time.h>#include "gntwm.h"#include "gntstyle.h"#include "gntmarshal.h"#include "gnt.h"#include "gntbox.h"#include "gntlabel.h"#include "gntmenu.h"#include "gnttextview.h"#include "gnttree.h"#include "gntutils.h"#include "gntwindow.h"#define IDLE_CHECK_INTERVAL 5 /* 5 seconds */enum{	SIG_NEW_WIN,	SIG_DECORATE_WIN,	SIG_CLOSE_WIN,	SIG_CONFIRM_RESIZE,	SIG_RESIZED,	SIG_CONFIRM_MOVE,	SIG_MOVED,	SIG_UPDATE_WIN,	SIG_GIVE_FOCUS,	SIG_KEY_PRESS,	SIG_MOUSE_CLICK,	SIGS};static guint signals[SIGS] = { 0 };static void gnt_wm_new_window_real(GntWM *wm, GntWidget *widget);static void gnt_wm_win_resized(GntWM *wm, GntNode *node);static void gnt_wm_win_moved(GntWM *wm, GntNode *node);static void gnt_wm_give_focus(GntWM *wm, GntWidget *widget);static void update_window_in_list(GntWM *wm, GntWidget *wid);static void shift_window(GntWM *wm, GntWidget *widget, int dir);#ifndef NO_WIDECHARstatic int widestringwidth(wchar_t *wide);#endifstatic gboolean write_already(gpointer data);static int write_timeout;static time_t last_active_time;static gboolean idle_update;static GList *g_list_bring_to_front(GList *list, gpointer data){	list = g_list_remove(list, data);	list = g_list_prepend(list, data);	return list;}static voidfree_node(gpointer data){	GntNode *node = data;	hide_panel(node->panel);	del_panel(node->panel);	g_free(node);}static voiddraw_taskbar(GntWM *wm, gboolean reposition){	static WINDOW *taskbar = NULL;	GList *iter;	int n, width = 0;	int i;	if (taskbar == NULL) {		taskbar = newwin(1, getmaxx(stdscr), getmaxy(stdscr) - 1, 0);	} else if (reposition) {		int Y_MAX = getmaxy(stdscr) - 1;		mvwin(taskbar, Y_MAX, 0);	}	wbkgdset(taskbar, '\0' | COLOR_PAIR(GNT_COLOR_NORMAL));	werase(taskbar);	n = g_list_length(wm->list);	if (n)		width = getmaxx(stdscr) / n;	for (i = 0, iter = wm->list; iter; iter = iter->next, i++)	{		GntWidget *w = iter->data;		int color;		const char *title;		if (w == wm->ordered->data) {			/* This is the current window in focus */			color = GNT_COLOR_TITLE;		} else if (GNT_WIDGET_IS_FLAG_SET(w, GNT_WIDGET_URGENT)) {			/* This is a window with the URGENT hint set */			color = GNT_COLOR_URGENT;		} else {			color = GNT_COLOR_NORMAL;		}		wbkgdset(taskbar, '\0' | COLOR_PAIR(color));		if (iter->next)			mvwhline(taskbar, 0, width * i, ' ' | COLOR_PAIR(color), width);		else			mvwhline(taskbar, 0, width * i, ' ' | COLOR_PAIR(color), getmaxx(stdscr) - width * i);		title = GNT_BOX(w)->title;		mvwprintw(taskbar, 0, width * i, "%s", title ? title : "<gnt>");		if (i)			mvwaddch(taskbar, 0, width *i - 1, ACS_VLINE | A_STANDOUT | COLOR_PAIR(GNT_COLOR_NORMAL));		update_window_in_list(wm, w);	}	wrefresh(taskbar);}static voidcopy_win(GntWidget *widget, GntNode *node){	WINDOW *src, *dst;	int shadow;	if (!node)		return;	src = widget->window;	dst = node->window;	shadow = gnt_widget_has_shadow(widget) ? 1 : 0;	copywin(src, dst, node->scroll, 0, 0, 0, getmaxy(dst) - 1, getmaxx(dst) - 1, 0);}/** * The following is a workaround for a bug in most versions of ncursesw. * Read about it in: http://article.gmane.org/gmane.comp.lib.ncurses.bugs/2751 *  * In short, if a panel hides one cell of a multi-cell character, then the rest * of the characters in that line get screwed. The workaround here is to erase * any such character preemptively. * * Caveat: If a wide character is erased, and the panel above it is moved enough * to expose the entire character, it is not always redrawn. */static voidwork_around_for_ncurses_bug(){#ifndef NO_WIDECHAR	PANEL *panel = NULL;	while ((panel = panel_below(panel)) != NULL) {		int sx, ex, sy, ey, w, y;		cchar_t ch;		PANEL *below = panel;		sx = panel->win->_begx;		ex = panel->win->_maxx + sx;		sy = panel->win->_begy;		ey = panel->win->_maxy + sy;		while ((below = panel_below(below)) != NULL) {			if (sy > below->win->_begy + below->win->_maxy ||					ey < below->win->_begy)				continue;			if (sx > below->win->_begx + below->win->_maxx ||					ex < below->win->_begx)				continue;			for (y = MAX(sy, below->win->_begy); y <= MIN(ey, below->win->_begy + below->win->_maxy); y++) {				if (mvwin_wch(below->win, y - below->win->_begy, sx - 1 - below->win->_begx, &ch) != OK)					goto right;				w = widestringwidth(ch.chars);				if (w > 1 && (ch.attr & 1)) {					ch.chars[0] = ' ';					ch.attr &= ~ A_CHARTEXT;					mvwadd_wch(below->win, y - below->win->_begy, sx - 1 - below->win->_begx, &ch);					touchline(below->win, y - below->win->_begy, 1);				}right:				if (mvwin_wch(below->win, y - below->win->_begy, ex + 1 - below->win->_begx, &ch) != OK)					continue;				w = widestringwidth(ch.chars);				if (w > 1 && !(ch.attr & 1)) {					ch.chars[0] = ' ';					ch.attr &= ~ A_CHARTEXT;					mvwadd_wch(below->win, y - below->win->_begy, ex + 1 - below->win->_begx, &ch);					touchline(below->win, y - below->win->_begy, 1);				}			}		}	}#endif}static gbooleanupdate_screen(GntWM *wm){	if (wm->menu) {		GntMenu *top = wm->menu;		while (top) {			GntNode *node = g_hash_table_lookup(wm->nodes, top);			if (node)				top_panel(node->panel);			top = top->submenu;		}	}	work_around_for_ncurses_bug();	update_panels();	doupdate();	return TRUE;}static gbooleansanitize_position(GntWidget *widget, int *x, int *y){	int X_MAX = getmaxx(stdscr);	int Y_MAX = getmaxy(stdscr) - 1;	int w, h;	int nx, ny;	gboolean changed = FALSE;	gnt_widget_get_size(widget, &w, &h);	if (x) {		if (*x + w > X_MAX) {			nx = MAX(0, X_MAX - w);			if (nx != *x) {				*x = nx;				changed = TRUE;			}		}	}	if (y) {		if (*y + h > Y_MAX) {			ny = MAX(0, Y_MAX - h);			if (ny != *y) {				*y = ny;				changed = TRUE;			}		}	}	return changed;}static voidrefresh_node(GntWidget *widget, GntNode *node, gpointer null){	int x, y, w, h;	int nw, nh;	int X_MAX = getmaxx(stdscr);	int Y_MAX = getmaxy(stdscr) - 1;	gnt_widget_get_position(widget, &x, &y);	gnt_widget_get_size(widget, &w, &h);	if (sanitize_position(widget, &x, &y))		gnt_screen_move_widget(widget, x, y);	nw = MIN(w, X_MAX);	nh = MIN(h, Y_MAX);	if (nw != w || nh != h)		gnt_screen_resize_widget(widget, nw, nh);}static voidread_window_positions(GntWM *wm){#if GLIB_CHECK_VERSION(2,6,0)	GKeyFile *gfile = g_key_file_new();	char *filename = g_build_filename(g_get_home_dir(), ".gntpositions", NULL);	GError *error = NULL;	char **keys;	gsize nk;	if (!g_key_file_load_from_file(gfile, filename, G_KEY_FILE_NONE, &error)) {		g_printerr("GntWM: %s\n", error->message);		g_error_free(error);		g_free(filename);		return;	}	keys = g_key_file_get_keys(gfile, "positions", &nk, &error);	if (error) {		g_printerr("GntWM: %s\n", error->message);		g_error_free(error);		error = NULL;	} else {		while (nk--) {			char *title = keys[nk];			gsize l;			char **coords = g_key_file_get_string_list(gfile, "positions", title, &l, NULL);			if (l == 2) {				int x = atoi(coords[0]);				int y = atoi(coords[1]);				GntPosition *p = g_new0(GntPosition, 1);				p->x = x;				p->y = y;				g_hash_table_replace(wm->positions, g_strdup(title + 1), p);			} else {				g_printerr("GntWM: Invalid number of arguments for positioing a window.\n");			}			g_strfreev(coords);		}		g_strfreev(keys);	}	g_free(filename);	g_key_file_free(gfile);#endif}static gboolean check_idle(gpointer n){	if (idle_update) {		time(&last_active_time);		idle_update = FALSE;	}	return TRUE;}static voidgnt_wm_init(GTypeInstance *instance, gpointer class){	GntWM *wm = GNT_WM(instance);	wm->list = NULL;	wm->ordered = NULL;	wm->event_stack = FALSE;	wm->windows = NULL;	wm->actions = NULL;	wm->nodes = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, free_node);	wm->positions = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);	if (gnt_style_get_bool(GNT_STYLE_REMPOS, TRUE))		read_window_positions(wm);	g_timeout_add(IDLE_CHECK_INTERVAL * 1000, check_idle, NULL);	time(&last_active_time);}static voidswitch_window(GntWM *wm, int direction){	GntWidget *w = NULL, *wid = NULL;	int pos;	if (wm->_list.window || wm->menu)		return;	if (!wm->ordered || !wm->ordered->next)		return;	w = wm->ordered->data;	pos = g_list_index(wm->list, w);	pos += direction;	if (pos < 0)		wid = g_list_last(wm->list)->data;	else if (pos >= g_list_length(wm->list))		wid = wm->list->data;	else if (pos >= 0)		wid = g_list_nth_data(wm->list, pos);	wm->ordered = g_list_bring_to_front(wm->ordered, wid);	gnt_wm_raise_window(wm, wm->ordered->data);	if (w != wid) {		gnt_widget_set_focus(w, FALSE);	}}static gbooleanwindow_next(GntBindable *bindable, GList *null){	GntWM *wm = GNT_WM(bindable);	switch_window(wm, 1);	return TRUE;}static gbooleanwindow_prev(GntBindable *bindable, GList *null){	GntWM *wm = GNT_WM(bindable);	switch_window(wm, -1);	return TRUE;}static gbooleanswitch_window_n(GntBindable *bind, GList *list){	GntWM *wm = GNT_WM(bind);	GntWidget *w = NULL;	GList *l;	int n;	if (!wm->ordered)		return TRUE;	if (list)		n = GPOINTER_TO_INT(list->data);	else		n = 0;	w = wm->ordered->data;	if ((l = g_list_nth(wm->list, n)) != NULL)	{		gnt_wm_raise_window(wm, l->data);	}	if (l && w != l->data)	{		gnt_widget_set_focus(w, FALSE);	}	return TRUE;}static gbooleanwindow_scroll_up(GntBindable *bindable, GList *null){	GntWM *wm = GNT_WM(bindable);	GntWidget *window;	GntNode *node;	if (!wm->ordered)		return TRUE;	window = wm->ordered->data;	node = g_hash_table_lookup(wm->nodes, window);	if (!node)		return TRUE;	if (node->scroll) {		node->scroll--;		copy_win(window, node);		update_screen(wm);	}	return TRUE;}static gbooleanwindow_scroll_down(GntBindable *bindable, GList *null){	GntWM *wm = GNT_WM(bindable);	GntWidget *window;	GntNode *node;	int w, h;	if (!wm->ordered)		return TRUE;	window = wm->ordered->data;	node = g_hash_table_lookup(wm->nodes, window);	if (!node)		return TRUE;	gnt_widget_get_size(window, &w, &h);	if (h - node->scroll > getmaxy(node->window)) {		node->scroll++;		copy_win(window, node);		update_screen(wm);	}	return TRUE;}static gbooleanwindow_close(GntBindable *bindable, GList *null){	GntWM *wm = GNT_WM(bindable);	if (wm->_list.window)		return TRUE;	if (wm->ordered) {		gnt_widget_destroy(wm->ordered->data);	}	return TRUE;}static gbooleanhelp_for_widget(GntBindable *bindable, GList *null){	GntWM *wm = GNT_WM(bindable);	GntWidget *widget, *tree, *win, *active;	char *title;	if (!wm->ordered)		return TRUE;	widget = wm->ordered->data;	if (!GNT_IS_BOX(widget))		return TRUE;	active = GNT_BOX(widget)->active;	tree = gnt_widget_bindings_view(active);	win = gnt_window_new();	title = g_strdup_printf("Bindings for %s", g_type_name(G_OBJECT_TYPE(active)));	gnt_box_set_title(GNT_BOX(win), title);	if (tree)		gnt_box_add_widget(GNT_BOX(win), tree);	else		gnt_box_add_widget(GNT_BOX(win), gnt_label_new("This widget has no customizable bindings."));	gnt_widget_show(win);	return TRUE;}static voiddestroy__list(GntWidget *widget, GntWM *wm){	wm->_list.window = NULL;	wm->_list.tree = NULL;	wm->windows = NULL;	wm->actions = NULL;	update_screen(wm);}static voidsetup__list(GntWM *wm){	GntWidget *tree, *win;	win = wm->_list.window = gnt_box_new(FALSE, FALSE);	gnt_box_set_toplevel(GNT_BOX(win), TRUE);	gnt_box_set_pad(GNT_BOX(win), 0);	GNT_WIDGET_SET_FLAGS(win, GNT_WIDGET_TRANSIENT);	tree = wm->_list.tree = gnt_tree_new();	gnt_box_add_widget(GNT_BOX(win), tree);	g_signal_connect(G_OBJECT(win), "destroy", G_CALLBACK(destroy__list), wm);}static voidwindow_list_activate(GntTree *tree, GntWM *wm){	GntWidget *widget = gnt_tree_get_selection_data(GNT_TREE(tree));	if (!wm->ordered || !widget)		return;	gnt_widget_destroy(wm->_list.window);	gnt_wm_raise_window(wm, widget);}static void

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -