view plugins/win32/winprefs/winprefs.c @ 8995:9caf796e74aa

[gaim-migrate @ 9770] "Luke, if you get a chance, could you commit this? It should improve the HTML escaping situation between Gaim and other AIM and ICQ clients. I haven't actually applied it locally or tested it, but it looks ok to me. I would do it myself, but there are other changes in my oscar.c that aren't ready to commit, and I want to go to sleep so I can wake up tomorrow... I'll probably be out of town climbing until Sunday night... "--Mark Doliner "Below is an email I nearly sent you, before deciding to test & document the failure cases I knew of. http://www.nosnilmot.com/gaim/oscar-html.txt shows how current CVS behaves sending the string "<foo>" between GaimICQ/GaimAIM/ICQLite/WinAIM in various combinations After that testing I couldn't help trying to fix it :) The attached patch, from my testing, resolves all those marked with "XX" so that what is received matches what the user sent. The code might not be the most efficient and may contain redundant bits but I've had enough of this for now, 2 Windows crashes which caused VMWare to be weird and half break my keyboard and require restarting X. The patch might want a bit more testing, especially with iChat (I'm unable to test with that). Maybe committing it to CVS might get it some more testing though ;-)" --Stu Tomlinson committer: Tailor Script <tailor@pidgin.im>
author Luke Schierer <lschiere@pidgin.im>
date Fri, 21 May 2004 11:55:08 +0000
parents 294ae6548d4e
children 10a1cd720ac6
line wrap: on
line source

/*
 * gaim - WinGaim Options Plugin
 *
 * File: winprefs.c
 * Date: December 12, 2002
 *
 * copyright (c) 2002-2003, Herman Bloggs <hermanator12002@yahoo.com>
 *
 * this program 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., 59 temple place, suite 330, boston, ma  02111-1307  usa
 *
 */
#include <gdk/gdkwin32.h>

#include "internal.h"
#include "gtkinternal.h"

#include "core.h"
#include "prefs.h"
#include "debug.h"
#include "signals.h"

#include "gtkplugin.h"
#include "gtkutils.h"
#include "gtkblist.h"
#include "gtkappbar.h"

/*
 *  MACROS & DEFINES
 */
#define WINPREFS_PLUGIN_ID               "gtk-win-prefs"

/*
 *  LOCALS
 */
static const char *OPT_WINPREFS_DBLIST_DOCKABLE =      "/plugins/gtk/win32/winprefs/dblist_dockable";
static const char *OPT_WINPREFS_DBLIST_DOCKED =        "/plugins/gtk/win32/winprefs/dblist_docked";
static const char *OPT_WINPREFS_DBLIST_HEIGHT =        "/plugins/gtk/win32/winprefs/dblist_height";
static const char *OPT_WINPREFS_DBLIST_SIDE =          "/plugins/gtk/win32/winprefs/dblist_side";
static const char *OPT_WINPREFS_DBLIST_ON_TOP =        "/plugins/gtk/win32/winprefs/dblist_on_top";
static const char *OPT_WINPREFS_BLIST_ON_TOP =         "/plugins/gtk/win32/winprefs/blist_on_top";
static const char *OPT_WINPREFS_IM_BLINK =             "/plugins/gtk/win32/winprefs/im_blink";

static GaimPlugin *plugin_id = NULL;
static GtkAppBar *blist_ab = NULL;
static GtkWidget *blist = NULL;

/*
 *  PROTOS
 */
static void blist_create_cb();

/*
 *  CODE
 */

/* UTIL */

static GtkWidget *wgaim_button(const char *text, GtkWidget *page) {
        GtkWidget *button;
	button = gtk_check_button_new_with_mnemonic(text);
        gtk_box_pack_start(GTK_BOX(page), button, FALSE, FALSE, 0);
	gtk_widget_show(button);
        return button;
}

/* BLIST DOCKING */

static void blist_save_state() {
        if(blist_ab) {
                if(gaim_prefs_get_bool(OPT_WINPREFS_DBLIST_DOCKABLE) && blist_ab->docked) {
                        gaim_prefs_set_int(OPT_WINPREFS_DBLIST_HEIGHT, blist_ab->undocked_height);
                        gaim_prefs_set_int(OPT_WINPREFS_DBLIST_SIDE, blist_ab->side);
                        gaim_prefs_set_bool(OPT_WINPREFS_DBLIST_DOCKED, blist_ab->docked);
                }
                else
                        gaim_prefs_set_bool(OPT_WINPREFS_DBLIST_DOCKED, FALSE);
        }
}

static void blist_set_ontop(gboolean val) {
        if(!blist)
                return;
        if(val)
                SetWindowPos(GDK_WINDOW_HWND(blist->window), HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
        else
                SetWindowPos(GDK_WINDOW_HWND(blist->window), HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
}

static void blist_dock_cb(gboolean val) {
        if(val) {
                gaim_debug_info(WINPREFS_PLUGIN_ID, "Blist Docking..\n");
                if(gaim_prefs_get_bool(OPT_WINPREFS_DBLIST_ON_TOP))
                        blist_set_ontop(TRUE);
        }
        else {
                gaim_debug_info(WINPREFS_PLUGIN_ID, "Blist Undocking..\n");
                if(gaim_prefs_get_bool(OPT_WINPREFS_DBLIST_ON_TOP) &&
                   !gaim_prefs_get_bool(OPT_WINPREFS_BLIST_ON_TOP))
                        blist_set_ontop(FALSE);
        }
}

static void blist_set_dockable(gboolean val) {
        if(val) {
                if(!blist_ab && blist) {
                        blist_ab = gtk_appbar_add(blist);
                        gtk_appbar_add_dock_cb(blist_ab, blist_dock_cb);
                }
        }
        else {
                if(gaim_prefs_get_bool(OPT_WINPREFS_DBLIST_ON_TOP) &&
                   !gaim_prefs_get_bool(OPT_WINPREFS_BLIST_ON_TOP))
                        blist_set_ontop(FALSE);
                gtk_appbar_remove(blist_ab);
                blist_ab = NULL;
        }
}

/* PLUGIN CALLBACKS */

/* We need this because the blist destroy cb won't be called before the
   plugin is unloaded, when quitting */
static void gaim_quit_cb() {
        gaim_debug_info(WINPREFS_PLUGIN_ID, "gaim_quit_cb: removing appbar\n");
        blist_save_state();
        blist_set_dockable(FALSE);
}

/* Needed when the last account is signed off.. and we get the login window */
static void blist_destroy_cb() {
        gaim_debug_info(WINPREFS_PLUGIN_ID, "blist_destroy_cb\n");
        blist_save_state();
        blist_set_dockable(FALSE);
        gaim_signal_connect((void*)gaim_connections_get_handle(), "signed-on", plugin_id, GAIM_CALLBACK(blist_create_cb), NULL);
}

static gboolean blist_create_cb_remove(gpointer data) {
        gaim_signal_disconnect(gaim_connections_get_handle(), "signed-on", plugin_id, GAIM_CALLBACK(blist_create_cb));
        return FALSE;
}

static void blist_create_cb() {
        gaim_debug_info(WINPREFS_PLUGIN_ID, "event_signon\n");

        blist = GAIM_GTK_BLIST(gaim_get_blist())->window;
        g_signal_connect(blist, "destroy", blist_destroy_cb, NULL);

        if(gaim_prefs_get_bool(OPT_WINPREFS_DBLIST_DOCKABLE)) {
                blist_set_dockable(TRUE);
                if(gaim_prefs_get_bool(OPT_WINPREFS_DBLIST_DOCKED)) {
                        blist_ab->undocked_height = gaim_prefs_get_int(OPT_WINPREFS_DBLIST_HEIGHT);
                        gtk_appbar_dock(blist_ab,
                                        gaim_prefs_get_int(OPT_WINPREFS_DBLIST_SIDE));
                        if(gaim_prefs_get_bool(OPT_WINPREFS_DBLIST_ON_TOP))
                                blist_set_ontop(TRUE);
                }
        }
        if(gaim_prefs_get_bool(OPT_WINPREFS_BLIST_ON_TOP)) {
                blist_set_ontop(TRUE);
        }
        /* removing here will cause a crash when going to next cb
           in the gaim signal cb loop.. so process delayed. */
        g_idle_add(blist_create_cb_remove, NULL);
}

/* AUTOSTART */

static int open_run_key(PHKEY phKey, REGSAM samDesired) {
        /* First try current user key (for WinNT & Win2k +), fall back to local machine */
        if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, 
					 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", 
					 0,  samDesired,  phKey));
	else if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, 
					      "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", 
					      0,  samDesired,  phKey));
	else {
		gaim_debug_error(WINPREFS_PLUGIN_ID, "open_run_key: Could not open key for writing value\n");
		return 0;
	}
	return 1;
}

/* WIN PREFS GENERAL */

static void winprefs_set_autostart(GtkWidget *w) {
        HKEY hKey;

        if(!open_run_key(&hKey, KEY_SET_VALUE))
                return;
        if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) {
                char buffer[1024];
                DWORD size;
                
                if((size = GetModuleFileName(wgaim_hinstance(),
                                             (LPBYTE)buffer,
                                             sizeof(buffer)))==0) {
                        gaim_debug_error(WINPREFS_PLUGIN_ID, "GetModuleFileName Error.. Could not set Gaim autostart.\n");
                        RegCloseKey(hKey);
                        return;
                }
                /* Now set value of new key */
                if(ERROR_SUCCESS != RegSetValueEx(hKey,
                                                  "Gaim",
                                                  0,
                                                  REG_SZ,
                                                  buffer,
                                                  size))
                        gaim_debug_error(WINPREFS_PLUGIN_ID, "Could not set registry key value\n");
        }
        else {
                if(ERROR_SUCCESS != RegDeleteValue(hKey, "Gaim"))
                        gaim_debug_error(WINPREFS_PLUGIN_ID, "Could not delete registry key value\n");
        }
        RegCloseKey(hKey);
}

static void winprefs_set_blist_dockable(GtkWidget *w, GtkWidget *w1) {
        gaim_prefs_set_bool(OPT_WINPREFS_DBLIST_DOCKABLE, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w)));
        if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) {
                blist_set_dockable(TRUE);
                gtk_widget_set_sensitive(w1, TRUE);
        }
        else {
                blist_set_dockable(FALSE);
                gtk_widget_set_sensitive(w1, FALSE);
        }
}

static void winprefs_set_blist_ontop(GtkWidget *w) {
        gaim_prefs_set_bool(OPT_WINPREFS_BLIST_ON_TOP, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w)));

        if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) {
                blist_set_ontop(TRUE);
        }
        else {
                if(!(gaim_prefs_get_bool(OPT_WINPREFS_DBLIST_DOCKABLE) &&
                     gaim_prefs_get_bool(OPT_WINPREFS_DBLIST_ON_TOP) &&
                     (blist_ab && blist_ab->docked)))
                        blist_set_ontop(FALSE);
        }
}

static void winprefs_set_dblist_ontop(GtkWidget *w) {
        gaim_prefs_set_bool(OPT_WINPREFS_DBLIST_ON_TOP, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w)));
        if(blist && blist_ab) {
                if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) {
                        if(blist_ab->docked)
                                blist_set_ontop(TRUE);
                }
                else if(!gaim_prefs_get_bool(OPT_WINPREFS_BLIST_ON_TOP))
                        blist_set_ontop(FALSE);
        }
}

static void winprefs_set_im_blink(GtkWidget *w) {
        gaim_prefs_set_bool(OPT_WINPREFS_IM_BLINK, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w)));
        wgaim_conv_im_blink_state(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w)));
}

/*
 *  EXPORTED FUNCTIONS
 */

gboolean plugin_load(GaimPlugin *plugin) {
        plugin_id = plugin;

        /* blist docking init */
        if(gaim_get_blist() && GAIM_GTK_BLIST(gaim_get_blist())) {
                blist = GAIM_GTK_BLIST(gaim_get_blist())->window;
                /* Set Dockable */
                if(gaim_prefs_get_bool(OPT_WINPREFS_DBLIST_DOCKABLE))
                        blist_set_dockable(TRUE);
                /* Set On top */
                if(gaim_prefs_get_bool(OPT_WINPREFS_BLIST_ON_TOP))
                        blist_set_ontop(TRUE);
                g_signal_connect(blist, "destroy", blist_destroy_cb, NULL);
        }
        else
                gaim_signal_connect((void*)gaim_connections_get_handle(), "signed-on", plugin_id, GAIM_CALLBACK(blist_create_cb), NULL);

        wgaim_conv_im_blink_state(gaim_prefs_get_bool(OPT_WINPREFS_IM_BLINK));

        gaim_signal_connect((void*)gaim_get_core(), "quitting", plugin, GAIM_CALLBACK(gaim_quit_cb), NULL);

        return TRUE;
}

gboolean plugin_unload(GaimPlugin *plugin) {
        blist_set_dockable(FALSE);
        wgaim_conv_im_blink_state(TRUE);
        return TRUE;
}

static GtkWidget* get_config_frame(GaimPlugin *plugin) {
	GtkWidget *ret;
	GtkWidget *button;
        GtkWidget *dbutton;
	GtkWidget *vbox;
        char* gtk_version = NULL;
        HKEY hKey = HKEY_CURRENT_USER;

	ret = gtk_vbox_new(FALSE, 18);
	gtk_container_set_border_width (GTK_CONTAINER (ret), 12);

        while(hKey) {
                char version[25];
                DWORD vlen = 25;
                if(wgaim_read_reg_string(hKey, "SOFTWARE\\GTK\\2.0", "Version", (LPBYTE)&version, &vlen)) {
                        char revision[25];
                        DWORD rlen = 25;
                        gboolean gotrev = FALSE;
                        if(wgaim_read_reg_string(hKey, "SOFTWARE\\GTK\\2.0", "Revision", (LPBYTE)&revision, &rlen)) {
                                revision[0] = g_ascii_toupper(revision[0]);
                                revision[1] = '\0';
                                gotrev = TRUE;
                        }
                        gtk_version = g_strdup_printf("%s%s%s", 
                                                      version, 
                                                      gotrev?" Revision ":"", 
                                                      gotrev?revision:"");
                        hKey = 0;
                }
                if(hKey == HKEY_CURRENT_USER)
                        hKey = HKEY_LOCAL_MACHINE;
                else if(hKey == HKEY_LOCAL_MACHINE)
                        hKey = 0;
        }

        /* Display Installed GTK+ Runtime Version */
        if(gtk_version) {
                GtkWidget *label;
                vbox = gaim_gtk_make_frame(ret, _("GTK+ Runtime Version"));
                label = gtk_label_new(gtk_version);
                gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
                gtk_widget_show(label);
                g_free(gtk_version);
        }

        /* Autostart */
	vbox = gaim_gtk_make_frame (ret, _("Startup"));
	button = wgaim_button(_("_Start Gaim on Windows startup"), vbox);
	if(open_run_key(&hKey, KEY_QUERY_VALUE)) {
		if(ERROR_SUCCESS == RegQueryValueEx(hKey, "Gaim", 0, NULL, NULL, NULL)) {
			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
		}
	}
	gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(winprefs_set_autostart), NULL);

        /* Buddy List */
	vbox = gaim_gtk_make_frame (ret, _("Buddy List"));
        button = wgaim_button(_("_Dockable Buddy List"), vbox);
        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), gaim_prefs_get_bool(OPT_WINPREFS_DBLIST_DOCKABLE));

        /* Docked Blist On Top */
        dbutton = wgaim_button(_("Docked _Buddy List is always on top"), vbox);
        gtk_signal_connect(GTK_OBJECT(dbutton), "clicked", GTK_SIGNAL_FUNC(winprefs_set_dblist_ontop), NULL);
        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dbutton), gaim_prefs_get_bool(OPT_WINPREFS_DBLIST_ON_TOP));
        if(!gaim_prefs_get_bool(OPT_WINPREFS_DBLIST_DOCKABLE))
                gtk_widget_set_sensitive(GTK_WIDGET(dbutton), FALSE);

        /* Connect cb for Dockable option.. passing dblist on top button */
        gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(winprefs_set_blist_dockable), dbutton);

        /* Blist On Top */
        button = wgaim_button(_("_Keep Buddy List window on top"), vbox);
        gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(winprefs_set_blist_ontop), NULL);
        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), gaim_prefs_get_bool(OPT_WINPREFS_BLIST_ON_TOP));

        /* Conversations */
	vbox = gaim_gtk_make_frame (ret, _("Conversations"));
        button = wgaim_button(_("_Flash Window when messages are received"), vbox);
        gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(winprefs_set_im_blink), NULL);
        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), gaim_prefs_get_bool(OPT_WINPREFS_IM_BLINK));

	gtk_widget_show_all(ret);
	return ret;
}

static GaimGtkPluginUiInfo ui_info =
{
	get_config_frame
};

static GaimPluginInfo info =
{
	GAIM_PLUGIN_API_VERSION,
	GAIM_PLUGIN_STANDARD,
	GAIM_GTK_PLUGIN_TYPE,
	0,
	NULL,
	GAIM_PRIORITY_DEFAULT,
	WINPREFS_PLUGIN_ID,
	N_("WinGaim Options"),
	VERSION,
	N_("Options specific to Windows Gaim."),
	N_("Options specific to Windows Gaim."),
	"Herman Bloggs <hermanator12002@yahoo.com>",
	GAIM_WEBSITE,
	plugin_load,
	plugin_unload,
	NULL,
	&ui_info,
	NULL,
	NULL,
	NULL
};

static void
init_plugin(GaimPlugin *plugin)
{
        gaim_prefs_add_none("/plugins/gtk/win32");
        gaim_prefs_add_none("/plugins/gtk/win32/winprefs");
        gaim_prefs_add_bool(OPT_WINPREFS_DBLIST_DOCKABLE, FALSE);
        gaim_prefs_add_bool(OPT_WINPREFS_DBLIST_DOCKED, FALSE);
        gaim_prefs_add_int(OPT_WINPREFS_DBLIST_HEIGHT, 0);
        gaim_prefs_add_int(OPT_WINPREFS_DBLIST_SIDE, 0);
        gaim_prefs_add_bool(OPT_WINPREFS_DBLIST_ON_TOP, FALSE);
        gaim_prefs_add_bool(OPT_WINPREFS_BLIST_ON_TOP, FALSE);
        gaim_prefs_add_bool(OPT_WINPREFS_IM_BLINK, TRUE);
}

GAIM_INIT_PLUGIN(winprefs, init_plugin, info)