pidgin/pidgin
Clone
Summary
Browse
Changes
Graph
Add a get_minimum_search_length to PurpleProtocolContacts
default
tip
26 hours ago, Gary Kramlich
5ebb4beb29b7
Add a get_minimum_search_length to PurpleProtocolContacts
This can be used by user interfaces, to not call
PurpleProtocolContacts.search_async with strings smaller than this length.
Testing Done:
Called in the turtles and ran the protocol_contacts test under valgrind.
Reviewed at https://reviews.imfreedom.org/r/3164/
/*
* Pidgin - Transparency plugin
*
* Copyright (C) 1998-2002, Rob Flynn <rob@marko.net>
* Copyright (C) 2002-2003, Herman Bloggs <hermanator12002@yahoo.com>
* Copyright (C) 2005, Daniel Atallah <daniel_atallah@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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02111-1301, USA.
*
*/
#include
<glib.h>
#include
<glib/gi18n-lib.h>
#include
<purple.h>
#include
<gplugin.h>
#include
<gplugin-native.h>
#include
<pidgin.h>
/*
* MACROS & DEFINES
*/
/* The plugin name is left unchanged from its WinAPI days in order to keep it
* loading for users who were using it. */
#define WINTRANS_PLUGIN_ID "gtk-win-trans"
/* Key used to save GtkEventControllerFocus for this plugin. */
#define WINTRANS_CONTROLLER_KEY (WINTRANS_PLUGIN_ID "-focus-controller")
/* Key used to save GtkSlider for this plugin. */
#define WINTRANS_SLIDER_KEY (WINTRANS_PLUGIN_ID "-slider")
/*
* LOCALS
*/
#define OPT_SCHEMA "im.pidgin.Pidgin.plugin.Transparency"
#define OPT_WINTRANS_ALPHA "alpha"
#define OPT_WINTRANS_SLIDER "slider"
#define OPT_WINTRANS_ONFOCUS "solid-on-focus"
/*
* CODE
*/
/* Set window transparency level */
static
void
set_wintrans
(
GtkWidget
*
window
,
int
alpha
,
gboolean
enabled
)
{
if
(
enabled
)
{
gtk_widget_set_opacity
(
window
,
alpha
/
255.0
);
}
else
{
gtk_widget_set_opacity
(
window
,
1
);
}
/* Changing from opaque to partially transparent seems to need some kind of
* structural refresh. Unfortunately, a simple `gtk_widget_queue_draw` is
* not sufficient, so we need to do this instead. */
gtk_widget_queue_resize
(
window
);
}
/* When a conv window is focused, if we're only transparent when unfocused,
* deal with transparency */
static
void
focus_conv_win_cb
(
GtkEventControllerFocus
*
self
,
gpointer
data
)
{
GtkWidget
*
window
=
NULL
;
gboolean
enter
=
GPOINTER_TO_INT
(
data
);
GSettings
*
settings
=
NULL
;
settings
=
g_settings_new_with_backend
(
OPT_SCHEMA
,
purple_core_get_settings_backend
());
if
(
!
g_settings_get_boolean
(
settings
,
OPT_WINTRANS_ONFOCUS
))
{
g_object_unref
(
settings
);
return
;
}
window
=
gtk_event_controller_get_widget
(
GTK_EVENT_CONTROLLER
(
self
));
set_wintrans
(
window
,
g_settings_get_int
(
settings
,
OPT_WINTRANS_ALPHA
),
!
enter
);
g_object_unref
(
settings
);
}
static
void
add_focus_controller_to_conv_win
(
GtkWidget
*
window
)
{
GtkEventController
*
focus
=
NULL
;
focus
=
gtk_event_controller_focus_new
();
g_signal_connect
(
focus
,
"enter"
,
G_CALLBACK
(
focus_conv_win_cb
),
GINT_TO_POINTER
(
TRUE
));
g_signal_connect
(
focus
,
"leave"
,
G_CALLBACK
(
focus_conv_win_cb
),
GINT_TO_POINTER
(
FALSE
));
gtk_widget_add_controller
(
window
,
focus
);
g_object_set_data
(
G_OBJECT
(
window
),
WINTRANS_CONTROLLER_KEY
,
focus
);
}
static
void
remove_focus_controller_from_conv_win
(
GtkWidget
*
window
)
{
GtkEventController
*
focus
=
NULL
;
focus
=
g_object_get_data
(
G_OBJECT
(
window
),
WINTRANS_CONTROLLER_KEY
);
if
(
GTK_IS_EVENT_CONTROLLER_FOCUS
(
focus
))
{
gtk_widget_remove_controller
(
window
,
focus
);
}
g_object_set_data
(
G_OBJECT
(
window
),
WINTRANS_CONTROLLER_KEY
,
NULL
);
}
static
void
change_alpha
(
GtkWidget
*
w
,
gpointer
data
)
{
int
alpha
=
gtk_range_get_value
(
GTK_RANGE
(
w
));
GSettings
*
settings
=
NULL
;
settings
=
g_settings_new_with_backend
(
OPT_SCHEMA
,
purple_core_get_settings_backend
());
g_settings_set_int
(
settings
,
OPT_WINTRANS_ALPHA
,
alpha
);
/* If we're in no-transparency on focus mode,
* don't take effect immediately */
if
(
!
g_settings_get_boolean
(
settings
,
OPT_WINTRANS_ONFOCUS
))
{
set_wintrans
(
GTK_WIDGET
(
data
),
alpha
,
TRUE
);
}
g_object_unref
(
settings
);
}
/* Clean up transparency stuff for the conv window */
static
void
conversation_delete_cb
(
G_GNUC_UNUSED
GtkApplication
*
application
,
GtkWindow
*
window
,
G_GNUC_UNUSED
gpointer
data
)
{
if
(
!
PIDGIN_IS_DISPLAY_WINDOW
(
window
))
{
return
;
}
purple_debug_info
(
WINTRANS_PLUGIN_ID
,
"Conv window destroyed... removing from list"
);
g_object_set_data
(
G_OBJECT
(
window
),
WINTRANS_SLIDER_KEY
,
NULL
);
/* Remove the focus cbs */
remove_focus_controller_from_conv_win
(
GTK_WIDGET
(
window
));
}
static
void
remove_slider
(
GtkWidget
*
slider_frame
)
{
gtk_widget_unparent
(
slider_frame
);
}
static
void
update_slider
(
GSettings
*
settings
,
gchar
*
key
,
gpointer
data
)
{
GtkWidget
*
slider
=
data
;
gint
alpha
=
255
;
alpha
=
g_settings_get_int
(
settings
,
key
);
gtk_range_set_value
(
GTK_RANGE
(
slider
),
alpha
);
}
static
void
add_slider
(
GtkWidget
*
win
)
{
GtkWidget
*
vbox
=
NULL
;
GtkWidget
*
slider_frame
;
GtkWidget
*
hbox
;
GtkWidget
*
label
,
*
slider
;
gint
imalpha
=
255
;
GSettings
*
settings
=
NULL
;
/* Look up this window to see if it already has a slider */
if
(
g_object_get_data
(
G_OBJECT
(
win
),
WINTRANS_SLIDER_KEY
)
!=
NULL
)
{
return
;
}
vbox
=
gtk_widget_get_first_child
(
win
);
while
(
vbox
!=
NULL
&&
!
GTK_IS_BOX
(
vbox
))
{
vbox
=
gtk_widget_get_next_sibling
(
vbox
);
}
if
(
vbox
==
NULL
)
{
purple_debug_error
(
WINTRANS_PLUGIN_ID
,
"no vbox found"
);
return
;
}
settings
=
g_settings_new_with_backend
(
OPT_SCHEMA
,
purple_core_get_settings_backend
());
slider_frame
=
gtk_frame_new
(
NULL
);
gtk_widget_set_margin_start
(
slider_frame
,
6
);
gtk_widget_set_margin_end
(
slider_frame
,
6
);
gtk_box_prepend
(
GTK_BOX
(
vbox
),
slider_frame
);
g_settings_bind
(
settings
,
OPT_WINTRANS_SLIDER
,
slider_frame
,
"visible"
,
G_SETTINGS_BIND_DEFAULT
);
hbox
=
gtk_box_new
(
GTK_ORIENTATION_HORIZONTAL
,
6
);
gtk_frame_set_child
(
GTK_FRAME
(
slider_frame
),
hbox
);
label
=
gtk_label_new
(
_
(
"Opacity:"
));
gtk_box_append
(
GTK_BOX
(
hbox
),
label
);
slider
=
gtk_scale_new_with_range
(
GTK_ORIENTATION_HORIZONTAL
,
50
,
255
,
1
);
gtk_widget_set_hexpand
(
slider
,
TRUE
);
gtk_box_append
(
GTK_BOX
(
hbox
),
slider
);
imalpha
=
g_settings_get_int
(
settings
,
OPT_WINTRANS_ALPHA
);
gtk_range_set_value
(
GTK_RANGE
(
slider
),
imalpha
);
/* On slider val change, update window's transparency level */
g_signal_connect
(
G_OBJECT
(
slider
),
"value-changed"
,
G_CALLBACK
(
change_alpha
),
win
);
/* We cannot use g_settings_bind because GtkScale has no value property. */
g_signal_connect_object
(
settings
,
"changed::"
OPT_WINTRANS_ALPHA
,
G_CALLBACK
(
update_slider
),
slider
,
0
);
/* Set the initial transparency level */
set_wintrans
(
win
,
g_settings_get_int
(
settings
,
OPT_WINTRANS_ALPHA
),
TRUE
);
/* Set window data, to track that it has a slider */
g_object_set_data_full
(
G_OBJECT
(
win
),
WINTRANS_SLIDER_KEY
,
slider_frame
,
(
GDestroyNotify
)
remove_slider
);
g_object_unref
(
settings
);
}
/* Remove all transparency related aspects from conversation windows */
static
void
remove_convs_wintrans
(
gboolean
remove_signal
)
{
GApplication
*
application
=
NULL
;
GList
*
wins
;
application
=
g_application_get_default
();
wins
=
gtk_application_get_windows
(
GTK_APPLICATION
(
application
));
for
(;
wins
;
wins
=
wins
->
next
)
{
GtkWidget
*
window
=
wins
->
data
;
if
(
!
PIDGIN_IS_DISPLAY_WINDOW
(
window
))
{
continue
;
}
set_wintrans
(
window
,
0
,
FALSE
);
/* Remove the focus cbs */
if
(
remove_signal
)
{
remove_focus_controller_from_conv_win
(
window
);
}
g_object_set_data
(
G_OBJECT
(
window
),
WINTRANS_SLIDER_KEY
,
NULL
);
}
}
static
void
set_conv_window_trans
(
GtkWidget
*
window
)
{
GSettings
*
settings
=
NULL
;
settings
=
g_settings_new_with_backend
(
OPT_SCHEMA
,
purple_core_get_settings_backend
());
set_wintrans
(
window
,
g_settings_get_int
(
settings
,
OPT_WINTRANS_ALPHA
),
TRUE
);
add_slider
(
window
);
g_object_unref
(
settings
);
}
static
void
new_conversation_cb
(
G_GNUC_UNUSED
GtkApplication
*
application
,
GtkWindow
*
window
,
G_GNUC_UNUSED
gpointer
data
)
{
if
(
!
PIDGIN_IS_DISPLAY_WINDOW
(
window
))
{
return
;
}
set_conv_window_trans
(
GTK_WIDGET
(
window
));
add_focus_controller_to_conv_win
(
GTK_WIDGET
(
window
));
}
static
void
update_existing_convs
(
void
)
{
GApplication
*
application
=
NULL
;
GList
*
wins
;
application
=
g_application_get_default
();
wins
=
gtk_application_get_windows
(
GTK_APPLICATION
(
application
));
for
(;
wins
;
wins
=
wins
->
next
)
{
GtkWidget
*
window
=
wins
->
data
;
if
(
!
PIDGIN_IS_DISPLAY_WINDOW
(
window
))
{
continue
;
}
set_conv_window_trans
(
window
);
add_focus_controller_to_conv_win
(
window
);
}
}
static
GPluginPluginInfo
*
transparency_query
(
G_GNUC_UNUSED
GError
**
error
)
{
const
gchar
*
const
authors
[]
=
{
"Pidgin Developers <devel@pidgin.im>"
,
NULL
};
return
purple_plugin_info_new
(
"id"
,
WINTRANS_PLUGIN_ID
,
"name"
,
N_
(
"Transparency"
),
"version"
,
DISPLAY_VERSION
,
"category"
,
N_
(
"User interface"
),
"summary"
,
N_
(
"Variable Transparency for the buddy list and conversations."
),
"description"
,
N_
(
"This plugin enables variable alpha transparency on conversation windows and the buddy list."
),
"authors"
,
authors
,
"website"
,
PURPLE_WEBSITE
,
"abi-version"
,
PURPLE_ABI_VERSION
,
"settings-schema"
,
OPT_SCHEMA
,
NULL
);
}
static
gboolean
transparency_load
(
G_GNUC_UNUSED
GPluginPlugin
*
plugin
,
G_GNUC_UNUSED
GError
**
error
)
{
GApplication
*
application
=
NULL
;
application
=
g_application_get_default
();
g_signal_connect
(
application
,
"window-added"
,
G_CALLBACK
(
new_conversation_cb
),
NULL
);
g_signal_connect
(
application
,
"window-removed"
,
G_CALLBACK
(
conversation_delete_cb
),
NULL
);
update_existing_convs
();
return
TRUE
;
}
static
gboolean
transparency_unload
(
G_GNUC_UNUSED
GPluginPlugin
*
plugin
,
G_GNUC_UNUSED
gboolean
shutdown
,
G_GNUC_UNUSED
GError
**
error
)
{
purple_debug_info
(
WINTRANS_PLUGIN_ID
,
"Unloading transparency plugin
\n
"
);
remove_convs_wintrans
(
TRUE
);
return
TRUE
;
}
GPLUGIN_NATIVE_PLUGIN_DECLARE
(
transparency
)