Mercurial > pidgin
view gtk/plugins/win32/winprefs/winprefs.c @ 14670:11fd4148f9da
[gaim-migrate @ 17416]
Don't dereference things before we check if they are NULL
committer: Tailor Script <tailor@pidgin.im>
author | Stu Tomlinson <stu@nosnilmot.com> |
---|---|
date | Sun, 01 Oct 2006 15:14:05 +0000 |
parents | 7635195195c0 |
children | 7fb8a8583c73 |
line wrap: on
line source
/* * gaim - WinGaim Options Plugin * * Gaim is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * source distribution. * * 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 <gtk/gtk.h> #include <gdk/gdkwin32.h> #include "internal.h" #include "gtkwin32dep.h" #include "core.h" #include "debug.h" #include "prefs.h" #include "signals.h" #include "version.h" #include "gtkappbar.h" #include "gtkblist.h" #include "gtkconv.h" #include "gtkplugin.h" #include "gtkprefs.h" #include "gtkutils.h" /* * MACROS & DEFINES */ #define WINPREFS_PLUGIN_ID "gtk-win-prefs" #define RUNKEY "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run" /* * LOCALS */ static const char *PREF_DBLIST_DOCKABLE = "/plugins/gtk/win32/winprefs/dblist_dockable"; static const char *PREF_DBLIST_DOCKED = "/plugins/gtk/win32/winprefs/dblist_docked"; static const char *PREF_DBLIST_HEIGHT = "/plugins/gtk/win32/winprefs/dblist_height"; static const char *PREF_DBLIST_SIDE = "/plugins/gtk/win32/winprefs/dblist_side"; static const char *PREF_BLIST_ON_TOP = "/plugins/gtk/win32/winprefs/blist_on_top"; static const char *PREF_IM_BLINK = "/plugins/gtk/win32/winprefs/im_blink"; static const char *PREF_CHAT_BLINK = "/plugins/gtk/win32/winprefs/chat_blink"; /* Deprecated */ static const char *PREF_DBLIST_ON_TOP = "/plugins/gtk/win32/winprefs/dblist_on_top"; static GaimPlugin *handle = NULL; static GtkAppBar *blist_ab = NULL; static GtkWidget *blist = NULL; static guint blist_visible_cb_id = 0; /* flash info */ struct _WGAIM_FLASH_INFO { guint t_handle; guint sig_handler; }; enum { BLIST_TOP_NEVER = 0, BLIST_TOP_ALWAYS, BLIST_TOP_DOCKED, }; typedef struct _WGAIM_FLASH_INFO WGAIM_FLASH_INFO; typedef BOOL (CALLBACK* LPFNFLASHWINDOWEX)(PFLASHWINFO); static LPFNFLASHWINDOWEX MyFlashWindowEx = NULL; /* * CODE */ /* BLIST DOCKING */ static void blist_save_state() { if(blist_ab) { if(gaim_prefs_get_bool(PREF_DBLIST_DOCKABLE) && blist_ab->docked) { gaim_prefs_set_int(PREF_DBLIST_HEIGHT, blist_ab->undocked_height); gaim_prefs_set_int(PREF_DBLIST_SIDE, blist_ab->side); gaim_prefs_set_bool(PREF_DBLIST_DOCKED, blist_ab->docked); } else gaim_prefs_set_bool(PREF_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_int(PREF_BLIST_ON_TOP) != BLIST_TOP_NEVER) blist_set_ontop(TRUE); } else { gaim_debug_info(WINPREFS_PLUGIN_ID, "Blist Undocking...\n"); if(gaim_prefs_get_int(PREF_BLIST_ON_TOP) == BLIST_TOP_ALWAYS) blist_set_ontop(TRUE); else blist_set_ontop(FALSE); } } static void blist_set_dockable(gboolean val) { if(val) { if(blist_ab == NULL && blist != NULL) { blist_ab = gtk_appbar_add(blist); gtk_appbar_add_dock_cb(blist_ab, blist_dock_cb); } } else { if(blist_ab != NULL) { gtk_appbar_remove(blist_ab); blist_ab = NULL; } if(gaim_prefs_get_int(PREF_BLIST_ON_TOP) == BLIST_TOP_ALWAYS) blist_set_ontop(TRUE); else blist_set_ontop(FALSE); } } /* 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); } /* Listen for the first time the window stops being withdrawn */ static void blist_visible_cb(const char *pref, GaimPrefType type, gconstpointer value, gpointer user_data) { if(gaim_prefs_get_bool(pref)) { gtk_appbar_dock(blist_ab, gaim_prefs_get_int(PREF_DBLIST_SIDE)); if(gaim_prefs_get_int(PREF_BLIST_ON_TOP) == BLIST_TOP_DOCKED) blist_set_ontop(TRUE); /* We only need to be notified about this once */ gaim_prefs_disconnect_callback(blist_visible_cb_id); } } /* This needs to be delayed otherwise, when the blist is originally created and * hidden, it'll trigger the blist_visible_cb */ static gboolean listen_for_blist_visible_cb(gpointer data) { if (handle != NULL) blist_visible_cb_id = gaim_prefs_connect_callback(handle, "/gaim/gtk/blist/list_visible", blist_visible_cb, NULL); return FALSE; } static void blist_create_cb(GaimBuddyList *gaim_blist, void *data) { gaim_debug_info(WINPREFS_PLUGIN_ID, "buddy list created\n"); blist = GAIM_GTK_BLIST(gaim_blist)->window; if(gaim_prefs_get_bool(PREF_DBLIST_DOCKABLE)) { blist_set_dockable(TRUE); if(gaim_prefs_get_bool(PREF_DBLIST_DOCKED)) { blist_ab->undocked_height = gaim_prefs_get_int(PREF_DBLIST_HEIGHT); if(!(gdk_window_get_state(blist->window) & GDK_WINDOW_STATE_WITHDRAWN)) { gtk_appbar_dock(blist_ab, gaim_prefs_get_int(PREF_DBLIST_SIDE)); if(gaim_prefs_get_int(PREF_BLIST_ON_TOP) == BLIST_TOP_DOCKED) blist_set_ontop(TRUE); } else { g_idle_add(listen_for_blist_visible_cb, NULL); } } } if(gaim_prefs_get_int(PREF_BLIST_ON_TOP) == BLIST_TOP_ALWAYS) blist_set_ontop(TRUE); } /* WIN PREFS GENERAL */ static void winprefs_set_autostart(GtkWidget *w) { char *runval = NULL; if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) runval = g_strdup_printf("%s" G_DIR_SEPARATOR_S "gaim.exe", wgaim_install_dir()); if(!wgaim_write_reg_string(HKEY_CURRENT_USER, RUNKEY, "Gaim", runval) /* For Win98 */ && !wgaim_write_reg_string(HKEY_LOCAL_MACHINE, RUNKEY, "Gaim", runval)) gaim_debug_error(WINPREFS_PLUGIN_ID, "Could not set registry key value\n"); g_free(runval); } static void winprefs_set_blist_dockable(const char *pref, GaimPrefType type, gconstpointer value, gpointer user_data) { blist_set_dockable(GPOINTER_TO_INT(value)); } static void winprefs_set_blist_ontop(const char *pref, GaimPrefType type, gconstpointer value, gpointer user_data) { gint setting = gaim_prefs_get_int(PREF_BLIST_ON_TOP); if((setting == BLIST_TOP_DOCKED && blist_ab && blist_ab->docked) || setting == BLIST_TOP_ALWAYS) blist_set_ontop(TRUE); else blist_set_ontop(FALSE); } static void load_winver_specific_procs(void) { /* Used for Win98+ and WinNT5+ */ MyFlashWindowEx = (LPFNFLASHWINDOWEX) wgaim_find_and_loadproc("user32.dll", "FlashWindowEx"); } /* Window flasher */ static gboolean flash_window_cb(gpointer data) { FlashWindow((HWND) data, TRUE); return TRUE; } static int halt_flash_filter(GtkWidget *widget, GdkEventFocus *event, gpointer data) { if(MyFlashWindowEx) { HWND hWnd = data; FLASHWINFO info; if(!IsWindow(hWnd)) return 0; memset(&info, 0, sizeof(FLASHWINFO)); info.cbSize = sizeof(FLASHWINFO); info.hwnd = hWnd; info.dwFlags = FLASHW_STOP; info.dwTimeout = 0; MyFlashWindowEx(&info); } else { WGAIM_FLASH_INFO *finfo = data; /* Stop flashing and remove filter */ gaim_debug(GAIM_DEBUG_INFO, "wgaim", "Removing timeout\n"); gaim_timeout_remove(finfo->t_handle); gaim_debug(GAIM_DEBUG_INFO, "wgaim", "Disconnecting signal handler\n"); g_signal_handler_disconnect(G_OBJECT(widget), finfo->sig_handler); gaim_debug(GAIM_DEBUG_INFO, "wgaim", "done\n"); g_free(finfo); } return 0; } /* FlashWindowEx is only supported by Win98+ and WinNT5+. If it's not supported we do it our own way */ static gboolean wgaim_conv_blink(GaimConversation *conv, int flags) { GaimGtkWindow *win; GtkWidget *window; /* Don't flash for our own messages or system messages */ if(flags & GAIM_MESSAGE_SEND || flags & GAIM_MESSAGE_SYSTEM) return FALSE; if(conv == NULL) { gaim_debug_info("winprefs", "gar!\n"); return FALSE; } win = gaim_gtkconv_get_window(GAIM_GTK_CONVERSATION(conv)); if(win == NULL) { gaim_debug_info("winprefs", "gar2!\n"); return FALSE; } window = win->window; if(MyFlashWindowEx) { FLASHWINFO info; if(GetForegroundWindow() == GDK_WINDOW_HWND(window->window)) return FALSE; memset(&info, 0, sizeof(FLASHWINFO)); info.cbSize = sizeof(FLASHWINFO); info.hwnd = GDK_WINDOW_HWND(window->window); info.dwFlags = FLASHW_ALL | FLASHW_TIMER; info.dwTimeout = 0; MyFlashWindowEx(&info); /* Stop flashing when window receives focus */ g_signal_connect(G_OBJECT(window), "focus-in-event", G_CALLBACK(halt_flash_filter), info.hwnd); } else { WGAIM_FLASH_INFO *finfo = g_new0(WGAIM_FLASH_INFO, 1); /* Start Flashing window */ finfo->t_handle = gaim_timeout_add(1000, flash_window_cb, GDK_WINDOW_HWND(window->window)); finfo->sig_handler = g_signal_connect(G_OBJECT(window), "focus-in-event", G_CALLBACK(halt_flash_filter), finfo); } return FALSE; } static gboolean wgaim_conv_im_blink(GaimAccount *account, const char *who, char **message, GaimConversation *conv, int flags, void *data) { if(!gaim_prefs_get_bool(PREF_IM_BLINK)) return FALSE; return wgaim_conv_blink(conv, flags); } static gboolean wgaim_conv_chat_blink(GaimAccount *account, const char *who, char **message, GaimConversation *conv, int flags, void *data) { if(!gaim_prefs_get_bool(PREF_CHAT_BLINK)) return FALSE; return wgaim_conv_blink(conv, flags); } /* * EXPORTED FUNCTIONS */ static gboolean plugin_load(GaimPlugin *plugin) { /* Find out how to go blinky */ load_winver_specific_procs(); handle = plugin; /* blist docking init */ if(gaim_get_blist() && GAIM_GTK_BLIST(gaim_get_blist()) && GAIM_GTK_BLIST(gaim_get_blist())->window) { blist_create_cb(gaim_get_blist(), NULL); } /* This really shouldn't happen anymore generally, but if for some strange reason, the blist is recreated, we need to set it up again. */ gaim_signal_connect(gaim_gtk_blist_get_handle(), "gtkblist-created", plugin, GAIM_CALLBACK(blist_create_cb), NULL); gaim_signal_connect(gaim_gtk_conversations_get_handle(), "displaying-im-msg", plugin, GAIM_CALLBACK(wgaim_conv_im_blink), NULL); gaim_signal_connect(gaim_gtk_conversations_get_handle(), "displaying-chat-msg", plugin, GAIM_CALLBACK(wgaim_conv_chat_blink), NULL); gaim_signal_connect((void*)gaim_get_core(), "quitting", plugin, GAIM_CALLBACK(gaim_quit_cb), NULL); gaim_prefs_connect_callback(handle, PREF_BLIST_ON_TOP, winprefs_set_blist_ontop, NULL); gaim_prefs_connect_callback(handle, PREF_DBLIST_DOCKABLE, winprefs_set_blist_dockable, NULL); return TRUE; } static gboolean plugin_unload(GaimPlugin *plugin) { blist_set_dockable(FALSE); blist_set_ontop(FALSE); handle = NULL; return TRUE; } static GtkWidget* get_config_frame(GaimPlugin *plugin) { GtkWidget *ret; GtkWidget *vbox; GtkWidget *button; char *gtk_version = NULL; char *run_key_val; ret = gtk_vbox_new(FALSE, 18); gtk_container_set_border_width(GTK_CONTAINER(ret), 12); gtk_version = g_strdup_printf("GTK+\t%u.%u.%u\nGlib\t%u.%u.%u", gtk_major_version, gtk_minor_version, gtk_micro_version, glib_major_version, glib_minor_version, glib_micro_version); /* 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 = gtk_check_button_new_with_mnemonic(_("_Start Gaim on Windows startup")); gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0); if ((run_key_val = wgaim_read_reg_string(HKEY_CURRENT_USER, RUNKEY, "Gaim")) || (run_key_val = wgaim_read_reg_string(HKEY_LOCAL_MACHINE, RUNKEY, "Gaim"))) { gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE); g_free(run_key_val); } g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(winprefs_set_autostart), NULL); gtk_widget_show(button); /* Buddy List */ vbox = gaim_gtk_make_frame(ret, _("Buddy List")); gaim_gtk_prefs_checkbox(_("_Dockable Buddy List"), PREF_DBLIST_DOCKABLE, vbox); /* Blist On Top */ gaim_gtk_prefs_dropdown(vbox, _("_Keep Buddy List window on top:"), GAIM_PREF_INT, PREF_BLIST_ON_TOP, _("Never"), BLIST_TOP_NEVER, _("Always"), BLIST_TOP_ALWAYS, /* XXX: Did this ever work? */ _("Only when docked"), BLIST_TOP_DOCKED, NULL); /* Conversations */ vbox = gaim_gtk_make_frame(ret, _("Conversations")); gaim_gtk_prefs_checkbox(_("_Flash window when IMs are received"), PREF_IM_BLINK, vbox); gaim_gtk_prefs_checkbox(_("_Flash window when chat messages are received"), PREF_CHAT_BLINK, vbox); gtk_widget_show_all(ret); return ret; } static GaimGtkPluginUiInfo ui_info = { get_config_frame, 0 }; static GaimPluginInfo info = { GAIM_PLUGIN_MAGIC, GAIM_MAJOR_VERSION, GAIM_MINOR_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_("Provides options specific to Windows Gaim, such as buddy list docking and conversation flashing."), "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"); gaim_prefs_add_none("/plugins/gtk/win32"); gaim_prefs_add_none("/plugins/gtk/win32/winprefs"); gaim_prefs_add_bool(PREF_DBLIST_DOCKABLE, FALSE); gaim_prefs_add_bool(PREF_DBLIST_DOCKED, FALSE); gaim_prefs_add_int(PREF_DBLIST_HEIGHT, 0); gaim_prefs_add_int(PREF_DBLIST_SIDE, 0); gaim_prefs_add_bool(PREF_IM_BLINK, TRUE); gaim_prefs_add_bool(PREF_CHAT_BLINK, FALSE); /* Convert old preferences */ if(gaim_prefs_exists(PREF_DBLIST_ON_TOP)) { gint blist_top = BLIST_TOP_NEVER; if(gaim_prefs_get_bool(PREF_BLIST_ON_TOP)) blist_top = BLIST_TOP_ALWAYS; else if(gaim_prefs_get_bool(PREF_DBLIST_ON_TOP)) blist_top = BLIST_TOP_DOCKED; gaim_prefs_remove(PREF_BLIST_ON_TOP); gaim_prefs_remove(PREF_DBLIST_ON_TOP); gaim_prefs_add_int(PREF_BLIST_ON_TOP, blist_top); } else gaim_prefs_add_int(PREF_BLIST_ON_TOP, BLIST_TOP_NEVER); } GAIM_INIT_PLUGIN(winprefs, init_plugin, info)