Adding upstream version 0.8.0.
[debian/lxpanel.git] / plugins / wincmd.c
CommitLineData
6cc5e1a6 1/**
6b775dbb 2 * Copyright (c) 2006-2014 LxDE Developers, see the file AUTHORS for details.
6cc5e1a6
DB
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
19#include <stdlib.h>
20
6cc5e1a6
DB
21#include <glib/gi18n.h>
22
6cc5e1a6
DB
23#include "misc.h"
24#include "plugin.h"
6cc5e1a6 25
2ba86315
DB
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. */
6cc5e1a6 34typedef struct {
6b775dbb 35 config_setting_t *settings; /* Settings array */
2ba86315
DB
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 */
39 gboolean toggle_preference; /* User preference: toggle iconify/shade and map */
40 gboolean toggle_state; /* State of toggle */
41} WinCmdPlugin;
6cc5e1a6 42
6b775dbb
AG
43static const char *wincmd_names[] = {
44 "none",
45 "iconify",
46 "shade"
6cc5e1a6
DB
47};
48
6b775dbb 49static void wincmd_destructor(gpointer user_data);
2ba86315 50
32a67dc7
DB
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
2ba86315
DB
60/* Execute a window command. */
61static void wincmd_execute(WinCmdPlugin * wc, WindowCommand command)
6cc5e1a6 62{
2ba86315
DB
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);
6b775dbb 66 Display *xdisplay = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
2ba86315
DB
67 if (client_list != NULL)
68 {
69 /* Loop over all windows. */
6b775dbb 70 int current_desktop = get_net_current_desktop();
2ba86315
DB
71 int i;
72 for (i = 0; i < client_count; i++)
73 {
74 /* Get the desktop and window type properties. */
75 NetWMWindowType nwwt;
6b775dbb 76 int task_desktop = get_net_wm_desktop(client_list[i]);
2ba86315
DB
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. */
81 if (((task_desktop == -1) || (task_desktop == current_desktop))
6b775dbb 82 && (( ! nwwt.dock) && ( ! nwwt.desktop) && ( ! nwwt.splash)))
2ba86315
DB
83 {
84 switch (command)
85 {
86 case WC_NONE:
87 break;
88
89 case WC_ICONIFY:
32a67dc7 90 if (( ! wc->toggle_preference) || ( ! wc->toggle_state))
6b775dbb 91 XIconifyWindow(xdisplay, client_list[i], DefaultScreen(xdisplay));
2ba86315 92 else
6b775dbb 93 XMapWindow (xdisplay, client_list[i]);
2ba86315
DB
94 break;
95
96 case WC_SHADE:
97 Xclimsg(client_list[i], a_NET_WM_STATE,
32a67dc7 98 ((( ! wc->toggle_preference) || ( ! wc->toggle_state)) ? a_NET_WM_STATE_ADD : a_NET_WM_STATE_REMOVE),
2ba86315
DB
99 a_NET_WM_STATE_SHADED, 0, 0, 0);
100 break;
101 }
102 }
6cc5e1a6 103 }
2ba86315 104 XFree(client_list);
6cc5e1a6 105
32a67dc7
DB
106 /* Adjust toggle state. */
107 wincmd_adjust_toggle_state(wc);
6cc5e1a6 108 }
6cc5e1a6
DB
109}
110
2ba86315 111/* Handler for "clicked" signal on main widget. */
6b775dbb 112static gboolean wincmd_button_clicked(GtkWidget * widget, GdkEventButton * event, LXPanel * panel)
6cc5e1a6 113{
6b775dbb 114 WinCmdPlugin * wc = lxpanel_plugin_get_data(widget);
6cc5e1a6 115
2ba86315
DB
116 /* Left-click to iconify. */
117 if (event->button == 1)
aa0e9095
DB
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
32a67dc7
DB
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))
aa0e9095 127 {
32a67dc7 128 int showing_desktop = ((( ! wc->toggle_preference) || ( ! wc->toggle_state)) ? 1 : 0);
6b775dbb
AG
129 Xclimsg(DefaultRootWindow(GDK_DISPLAY_XDISPLAY(gdk_display_get_default())),
130 a_NET_SHOWING_DESKTOP, showing_desktop, 0, 0, 0, 0);
32a67dc7 131 wincmd_adjust_toggle_state(wc);
aa0e9095
DB
132 }
133 else
aa0e9095 134 wincmd_execute(wc, WC_ICONIFY);
aa0e9095 135 }
6cc5e1a6 136
2ba86315
DB
137 /* Middle-click to shade. */
138 else if (event->button == 2)
139 wincmd_execute(wc, WC_SHADE);
140
141 return TRUE;
6cc5e1a6
DB
142}
143
2ba86315 144/* Plugin constructor. */
6b775dbb 145static GtkWidget *wincmd_constructor(LXPanel *panel, config_setting_t *settings)
2ba86315
DB
146{
147 /* Allocate plugin context and set into Plugin private data pointer. */
148 WinCmdPlugin * wc = g_new0(WinCmdPlugin, 1);
6b775dbb
AG
149 GtkWidget * p;
150 const char *str;
151 int tmp_int;
6cc5e1a6 152
2ba86315
DB
153 /* Initialize to defaults. */
154 wc->button_1_command = WC_ICONIFY;
155 wc->button_2_command = WC_SHADE;
6cc5e1a6 156
2ba86315 157 /* Load parameters from the configuration file. */
6b775dbb 158 if (config_setting_lookup_string(settings, "Button1", &str))
6cc5e1a6 159 {
6b775dbb
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 */
165 }
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;
6cc5e1a6 172 }
6b775dbb
AG
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;
6cc5e1a6 177
2ba86315
DB
178 /* Default the image if unspecified. */
179 if (wc->image == NULL)
180 wc->image = g_strdup("window-manager");
6cc5e1a6 181
6b775dbb
AG
182 /* Save construction pointers */
183 wc->settings = settings;
184
2ba86315 185 /* Allocate top level widget and set into Plugin widget pointer. */
6b775dbb
AG
186 p = lxpanel_button_new_for_icon(panel, wc->image, NULL, NULL);
187 lxpanel_plugin_set_data(p, wc, wincmd_destructor);
6b775dbb 188 gtk_widget_set_tooltip_text(p, _("Left click to iconify all windows. Middle click to shade them."));
6cc5e1a6 189
2ba86315 190 /* Show the widget and return. */
6b775dbb 191 return p;
2ba86315 192}
6cc5e1a6 193
2ba86315 194/* Plugin destructor. */
6b775dbb 195static void wincmd_destructor(gpointer user_data)
2ba86315 196{
6b775dbb 197 WinCmdPlugin * wc = user_data;
2ba86315
DB
198 g_free(wc->image);
199 g_free(wc);
200}
6cc5e1a6 201
2ba86315 202/* Callback when the configuration dialog has recorded a configuration change. */
6b775dbb 203static gboolean wincmd_apply_configuration(gpointer user_data)
2ba86315 204{
6b775dbb
AG
205 GtkWidget * p = user_data;
206 WinCmdPlugin * wc = lxpanel_plugin_get_data(p);
207
f7ecd6ce 208 //lxpanel_button_set_icon(p, wc->image, -1);
6b775dbb 209 /* Just save settings */
f7ecd6ce 210 //config_group_set_string(wc->settings, "image", wc->image);
6b775dbb
AG
211 config_group_set_string(wc->settings, "Button1",
212 wincmd_names[wc->button_1_command]);
213 config_group_set_string(wc->settings, "Button2",
214 wincmd_names[wc->button_2_command]);
215 config_group_set_int(wc->settings, "Toggle", wc->toggle_preference);
216 return FALSE;
6cc5e1a6
DB
217}
218
2ba86315 219/* Callback when the configuration dialog is to be shown. */
6b775dbb 220static GtkWidget *wincmd_configure(LXPanel *panel, GtkWidget *p)
6cc5e1a6 221{
6b775dbb
AG
222 WinCmdPlugin * wc = lxpanel_plugin_get_data(p);
223 return lxpanel_generic_config_dlg(_("Minimize All Windows"),
224 panel, wincmd_apply_configuration, p,
2ba86315 225 _("Alternately iconify/shade and raise"), &wc->toggle_preference, CONF_TYPE_BOOL,
6b775dbb 226 /* FIXME: configure buttons 1 and 2 */
2ba86315 227 NULL);
2ba86315
DB
228}
229
6cc5e1a6 230
2ba86315 231/* Plugin descriptor. */
6b775dbb
AG
232LXPanelPluginInit lxpanel_static_plugin_wincmd = {
233 .name = N_("Minimize All Windows"),
234 .description = N_("Sends commands to all desktop windows.\nSupported commands are 1) iconify and 2) shade"),
235
236 .new_instance = wincmd_constructor,
237 .config = wincmd_configure,
6b775dbb 238 .button_press_event = wincmd_button_clicked
6cc5e1a6 239};