Simplify 'cpufreq' plugin using lxpanel_button_new_for_icon().
[lxde/lxpanel.git] / plugins / wincmd.c
CommitLineData
239cb032 1/**
b8c2e0be 2 * Copyright (c) 2006-2014 LxDE Developers, see the file AUTHORS for details.
a99ee9e1
JH
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
a52c2257
HJYP
19#include <stdlib.h>
20
e7cb732b 21#include <glib/gi18n.h>
a52c2257 22
a52c2257 23#include "misc.h"
b8c2e0be 24#include "plugin.h"
a52c2257 25
2918994e 26/* Commands that can be issued. */
27typedef enum {
28 WC_NONE,
29 WC_ICONIFY,
30 WC_SHADE
31} WindowCommand;
32
33/* Private context for window command plugin. */
a52c2257 34typedef struct {
b8c2e0be 35 config_setting_t *settings; /* Settings array */
2918994e 36 char * image; /* Main icon */
37 WindowCommand button_1_command; /* Command for mouse button 1 */
38 WindowCommand button_2_command; /* Command for mouse button 2 */
ea20096e 39 gboolean toggle_preference; /* User preference: toggle iconify/shade and map */
40 gboolean toggle_state; /* State of toggle */
2918994e 41} WinCmdPlugin;
42
b8c2e0be
AG
43static const char *wincmd_names[] = {
44 "none",
45 "iconify",
46 "shade"
a52c2257
HJYP
47};
48
b8c2e0be 49static void wincmd_destructor(gpointer user_data);
8f9e6256 50
6e76a9e2
MJ
51/* Adjust the toggle state after a window command. */
52static void wincmd_adjust_toggle_state(WinCmdPlugin * wc)
53{
54 /* Ensure that if the user changes the preference from "unconditional" to "toggle", we do a raise on the next click. */
55 if (wc->toggle_preference)
56 wc->toggle_state = ! wc->toggle_state;
57 else wc->toggle_state = TRUE;
58}
59
2918994e 60/* Execute a window command. */
ea20096e 61static void wincmd_execute(WinCmdPlugin * wc, WindowCommand command)
a52c2257 62{
2918994e 63 /* Get the list of all windows. */
64 int client_count;
65 Window * client_list = get_xaproperty (GDK_ROOT_WINDOW(), a_NET_CLIENT_LIST, XA_WINDOW, &client_count);
09fa171b 66 Display *xdisplay = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
2918994e 67 if (client_list != NULL)
68 {
69 /* Loop over all windows. */
b8c2e0be 70 int current_desktop = get_net_current_desktop();
2918994e 71 int i;
72 for (i = 0; i < client_count; i++)
73 {
74 /* Get the desktop and window type properties. */
75 NetWMWindowType nwwt;
b8c2e0be 76 int task_desktop = get_net_wm_desktop(client_list[i]);
2918994e 77 get_net_wm_window_type(client_list[i], &nwwt);
78
79 /* If the task is visible on the current desktop and it is an ordinary window,
80 * execute the requested Iconify or Shade change. */
18ecfe2a 81 if (((task_desktop == -1) || (task_desktop == current_desktop))
06e29ce1 82 && (( ! nwwt.dock) && ( ! nwwt.desktop) && ( ! nwwt.splash)))
2918994e 83 {
84 switch (command)
85 {
18ecfe2a 86 case WC_NONE:
87 break;
88
2918994e 89 case WC_ICONIFY:
6e76a9e2 90 if (( ! wc->toggle_preference) || ( ! wc->toggle_state))
09fa171b 91 XIconifyWindow(xdisplay, client_list[i], DefaultScreen(xdisplay));
ea20096e 92 else
09fa171b 93 XMapWindow (xdisplay, client_list[i]);
18ecfe2a 94 break;
2918994e 95
96 case WC_SHADE:
97 Xclimsg(client_list[i], a_NET_WM_STATE,
6e76a9e2 98 ((( ! wc->toggle_preference) || ( ! wc->toggle_state)) ? a_NET_WM_STATE_ADD : a_NET_WM_STATE_REMOVE),
2918994e 99 a_NET_WM_STATE_SHADED, 0, 0, 0);
100 break;
101 }
102 }
a52c2257 103 }
2918994e 104 XFree(client_list);
ea20096e 105
6e76a9e2
MJ
106 /* Adjust toggle state. */
107 wincmd_adjust_toggle_state(wc);
a52c2257 108 }
a52c2257
HJYP
109}
110
2918994e 111/* Handler for "clicked" signal on main widget. */
a7bd16a4 112static gboolean wincmd_button_clicked(GtkWidget * widget, GdkEventButton * event, LXPanel * panel)
a52c2257 113{
1639d6b3 114 WinCmdPlugin * wc = lxpanel_plugin_get_data(widget);
b8c2e0be 115
2918994e 116 /* Left-click to iconify. */
117 if (event->button == 1)
53b37ef2
HJYP
118 {
119 GdkScreen* screen = gtk_widget_get_screen(widget);
120 static GdkAtom atom = 0;
121 if( G_UNLIKELY(0 == atom) )
122 atom = gdk_atom_intern("_NET_SHOWING_DESKTOP", FALSE);
123
6e76a9e2
MJ
124 /* If window manager supports _NET_SHOWING_DESKTOP, use it.
125 * Otherwise, fall back to iconifying windows individually. */
126 if (gdk_x11_screen_supports_net_wm_hint(screen, atom))
53b37ef2 127 {
6e76a9e2 128 int showing_desktop = ((( ! wc->toggle_preference) || ( ! wc->toggle_state)) ? 1 : 0);
09fa171b
AG
129 Xclimsg(DefaultRootWindow(GDK_DISPLAY_XDISPLAY(gdk_display_get_default())),
130 a_NET_SHOWING_DESKTOP, showing_desktop, 0, 0, 0, 0);
6e76a9e2 131 wincmd_adjust_toggle_state(wc);
53b37ef2
HJYP
132 }
133 else
53b37ef2 134 wincmd_execute(wc, WC_ICONIFY);
53b37ef2 135 }
a52c2257 136
2918994e 137 /* Middle-click to shade. */
138 else if (event->button == 2)
ea20096e 139 wincmd_execute(wc, WC_SHADE);
a52c2257 140
2918994e 141 return TRUE;
a52c2257
HJYP
142}
143
2918994e 144/* Plugin constructor. */
a7bd16a4 145static GtkWidget *wincmd_constructor(LXPanel *panel, config_setting_t *settings)
2918994e 146{
147 /* Allocate plugin context and set into Plugin private data pointer. */
148 WinCmdPlugin * wc = g_new0(WinCmdPlugin, 1);
b8c2e0be
AG
149 GtkWidget * p;
150 const char *str;
151 int tmp_int;
a52c2257 152
2918994e 153 /* Initialize to defaults. */
154 wc->button_1_command = WC_ICONIFY;
155 wc->button_2_command = WC_SHADE;
a52c2257 156
2918994e 157 /* Load parameters from the configuration file. */
b8c2e0be 158 if (config_setting_lookup_string(settings, "Button1", &str))
db449f6e 159 {
b8c2e0be
AG
160 if (g_ascii_strcasecmp(str, "shade") == 0)
161 wc->button_1_command = WC_SHADE;
162 else if (g_ascii_strcasecmp(str, "none") == 0)
163 wc->button_1_command = WC_NONE;
164 /* default is WC_ICONIFY */
a52c2257 165 }
b8c2e0be
AG
166 if (config_setting_lookup_string(settings, "Button2", &str))
167 {
168 if (g_ascii_strcasecmp(str, "iconify") == 0)
169 wc->button_2_command = WC_ICONIFY;
170 else if (g_ascii_strcasecmp(str, "none") == 0)
171 wc->button_2_command = WC_NONE;
172 }
173 if (config_setting_lookup_string(settings, "image", &str))
174 wc->image = expand_tilda(str);
175 if (config_setting_lookup_int(settings, "Toggle", &tmp_int))
176 wc->toggle_preference = tmp_int != 0;
5297da29 177
2918994e 178 /* Default the image if unspecified. */
179 if (wc->image == NULL)
180 wc->image = g_strdup("window-manager");
fcf6205e 181
b8c2e0be
AG
182 /* Save construction pointers */
183 wc->settings = settings;
184
2918994e 185 /* Allocate top level widget and set into Plugin widget pointer. */
b8c2e0be
AG
186 p = lxpanel_button_new_for_icon(panel, wc->image, NULL, NULL);
187 lxpanel_plugin_set_data(p, wc, wincmd_destructor);
188 gtk_container_set_border_width(GTK_CONTAINER(p), 0);
189 gtk_widget_set_tooltip_text(p, _("Left click to iconify all windows. Middle click to shade them."));
4542c20d 190
2918994e 191 /* Show the widget and return. */
b8c2e0be 192 return p;
a52c2257
HJYP
193}
194
2918994e 195/* Plugin destructor. */
b8c2e0be 196static void wincmd_destructor(gpointer user_data)
9c97f69e 197{
b8c2e0be 198 WinCmdPlugin * wc = user_data;
2918994e 199 g_free(wc->image);
200 g_free(wc);
9c97f69e
HJYP
201}
202
ea20096e 203/* Callback when the configuration dialog has recorded a configuration change. */
b8c2e0be 204static gboolean wincmd_apply_configuration(gpointer user_data)
ea20096e 205{
b8c2e0be
AG
206 GtkWidget * p = user_data;
207 WinCmdPlugin * wc = lxpanel_plugin_get_data(p);
208
88f6fc06 209 //lxpanel_button_set_icon(p, wc->image, -1);
b8c2e0be 210 /* Just save settings */
88f6fc06 211 //config_group_set_string(wc->settings, "image", wc->image);
a8d4af54
AG
212 config_group_set_string(wc->settings, "Button1",
213 wincmd_names[wc->button_1_command]);
214 config_group_set_string(wc->settings, "Button2",
215 wincmd_names[wc->button_2_command]);
216 config_group_set_int(wc->settings, "Toggle", wc->toggle_preference);
b8c2e0be 217 return FALSE;
ea20096e 218}
219
220/* Callback when the configuration dialog is to be shown. */
752ee4e2 221static GtkWidget *wincmd_configure(LXPanel *panel, GtkWidget *p)
ea20096e 222{
b8c2e0be 223 WinCmdPlugin * wc = lxpanel_plugin_get_data(p);
131514c9 224 return lxpanel_generic_config_dlg(_("Minimize All Windows"),
b8c2e0be 225 panel, wincmd_apply_configuration, p,
ea20096e 226 _("Alternately iconify/shade and raise"), &wc->toggle_preference, CONF_TYPE_BOOL,
b8c2e0be 227 /* FIXME: configure buttons 1 and 2 */
ea20096e 228 NULL);
ea20096e 229}
230
231
2918994e 232/* Plugin descriptor. */
b8c2e0be 233LXPanelPluginInit lxpanel_static_plugin_wincmd = {
3c3e9c9e 234 .name = N_("Minimize All Windows"),
3c3e9c9e
HG
235 .description = N_("Sends commands to all desktop windows.\nSupported commands are 1) iconify and 2) shade"),
236
b8c2e0be 237 .new_instance = wincmd_constructor,
3c3e9c9e 238 .config = wincmd_configure,
b8c2e0be 239 .button_press_event = wincmd_button_clicked
a52c2257 240};