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