Adding upstream version 0.9.0.
[debian/lxpanel.git] / plugins / wincmd.c
CommitLineData
0688b017
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>
7a1c5048 9 * 2014-2016 Andriy Grytsenko <andrej@rep.kiev.ua>
0688b017
AG
10 *
11 * This file is a part of LXPanel project.
6cc5e1a6
DB
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
28#include <stdlib.h>
29
6cc5e1a6
DB
30#include <glib/gi18n.h>
31
6cc5e1a6
DB
32#include "misc.h"
33#include "plugin.h"
6cc5e1a6 34
2ba86315
DB
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. */
6cc5e1a6 43typedef struct {
6b775dbb 44 config_setting_t *settings; /* Settings array */
2ba86315
DB
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 */
48 gboolean toggle_preference; /* User preference: toggle iconify/shade and map */
49 gboolean toggle_state; /* State of toggle */
50} WinCmdPlugin;
6cc5e1a6 51
6b775dbb
AG
52static const char *wincmd_names[] = {
53 "none",
54 "iconify",
55 "shade"
6cc5e1a6
DB
56};
57
6b775dbb 58static void wincmd_destructor(gpointer user_data);
2ba86315 59
32a67dc7
DB
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
2ba86315 69/* Execute a window command. */
7a1c5048 70static void wincmd_execute(GdkScreen * screen, WinCmdPlugin * wc, WindowCommand command)
6cc5e1a6 71{
2ba86315
DB
72 /* Get the list of all windows. */
73 int client_count;
7a1c5048
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);
2ba86315
DB
77 if (client_list != NULL)
78 {
79 /* Loop over all windows. */
6b775dbb 80 int current_desktop = get_net_current_desktop();
2ba86315
DB
81 int i;
82 for (i = 0; i < client_count; i++)
83 {
84 /* Get the desktop and window type properties. */
85 NetWMWindowType nwwt;
6b775dbb 86 int task_desktop = get_net_wm_desktop(client_list[i]);
2ba86315
DB
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. */
91 if (((task_desktop == -1) || (task_desktop == current_desktop))
6b775dbb 92 && (( ! nwwt.dock) && ( ! nwwt.desktop) && ( ! nwwt.splash)))
2ba86315
DB
93 {
94 switch (command)
95 {
96 case WC_NONE:
97 break;
98
99 case WC_ICONIFY:
32a67dc7 100 if (( ! wc->toggle_preference) || ( ! wc->toggle_state))
6b775dbb 101 XIconifyWindow(xdisplay, client_list[i], DefaultScreen(xdisplay));
2ba86315 102 else
6b775dbb 103 XMapWindow (xdisplay, client_list[i]);
2ba86315
DB
104 break;
105
106 case WC_SHADE:
7a1c5048 107 Xclimsgx(xscreen, client_list[i], a_NET_WM_STATE,
32a67dc7 108 ((( ! wc->toggle_preference) || ( ! wc->toggle_state)) ? a_NET_WM_STATE_ADD : a_NET_WM_STATE_REMOVE),
2ba86315
DB
109 a_NET_WM_STATE_SHADED, 0, 0, 0);
110 break;
111 }
112 }
6cc5e1a6 113 }
2ba86315 114 XFree(client_list);
6cc5e1a6 115
32a67dc7
DB
116 /* Adjust toggle state. */
117 wincmd_adjust_toggle_state(wc);
6cc5e1a6 118 }
6cc5e1a6
DB
119}
120
2ba86315 121/* Handler for "clicked" signal on main widget. */
6b775dbb 122static gboolean wincmd_button_clicked(GtkWidget * widget, GdkEventButton * event, LXPanel * panel)
6cc5e1a6 123{
6b775dbb 124 WinCmdPlugin * wc = lxpanel_plugin_get_data(widget);
6cc5e1a6 125
2ba86315
DB
126 /* Left-click to iconify. */
127 if (event->button == 1)
aa0e9095
DB
128 {
129 GdkScreen* screen = gtk_widget_get_screen(widget);
7a1c5048 130 Screen *xscreen = GDK_SCREEN_XSCREEN(screen);
aa0e9095
DB
131 static GdkAtom atom = 0;
132 if( G_UNLIKELY(0 == atom) )
133 atom = gdk_atom_intern("_NET_SHOWING_DESKTOP", FALSE);
134
32a67dc7
DB
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))
aa0e9095 138 {
32a67dc7 139 int showing_desktop = ((( ! wc->toggle_preference) || ( ! wc->toggle_state)) ? 1 : 0);
7a1c5048 140 Xclimsgx(xscreen, RootWindowOfScreen(xscreen),
6b775dbb 141 a_NET_SHOWING_DESKTOP, showing_desktop, 0, 0, 0, 0);
32a67dc7 142 wincmd_adjust_toggle_state(wc);
aa0e9095
DB
143 }
144 else
7a1c5048
AG
145 wincmd_execute(screen, wc, WC_ICONIFY);
146 return TRUE;
aa0e9095 147 }
6cc5e1a6 148
7a1c5048
AG
149 return FALSE;
150}
151
152static gboolean wincmd_button_released(GtkWidget * widget, GdkEventButton * event, WinCmdPlugin * wc)
153{
2ba86315 154 /* Middle-click to shade. */
7a1c5048
AG
155 if (event->button == 2)
156 {
157 wincmd_execute(gtk_widget_get_screen(widget), wc, WC_SHADE);
158 }
2ba86315 159
7a1c5048 160 return FALSE;
6cc5e1a6
DB
161}
162
2ba86315 163/* Plugin constructor. */
6b775dbb 164static GtkWidget *wincmd_constructor(LXPanel *panel, config_setting_t *settings)
2ba86315
DB
165{
166 /* Allocate plugin context and set into Plugin private data pointer. */
167 WinCmdPlugin * wc = g_new0(WinCmdPlugin, 1);
6b775dbb
AG
168 GtkWidget * p;
169 const char *str;
170 int tmp_int;
6cc5e1a6 171
2ba86315
DB
172 /* Initialize to defaults. */
173 wc->button_1_command = WC_ICONIFY;
174 wc->button_2_command = WC_SHADE;
6cc5e1a6 175
2ba86315 176 /* Load parameters from the configuration file. */
6b775dbb 177 if (config_setting_lookup_string(settings, "Button1", &str))
6cc5e1a6 178 {
6b775dbb
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 */
184 }
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;
6cc5e1a6 191 }
6b775dbb
AG
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;
6cc5e1a6 196
2ba86315
DB
197 /* Default the image if unspecified. */
198 if (wc->image == NULL)
199 wc->image = g_strdup("window-manager");
6cc5e1a6 200
6b775dbb
AG
201 /* Save construction pointers */
202 wc->settings = settings;
203
2ba86315 204 /* Allocate top level widget and set into Plugin widget pointer. */
6b775dbb
AG
205 p = lxpanel_button_new_for_icon(panel, wc->image, NULL, NULL);
206 lxpanel_plugin_set_data(p, wc, wincmd_destructor);
6b775dbb 207 gtk_widget_set_tooltip_text(p, _("Left click to iconify all windows. Middle click to shade them."));
6cc5e1a6 208
7a1c5048
AG
209 g_signal_connect(G_OBJECT(p), "button-release-event",
210 G_CALLBACK(wincmd_button_released), wc);
211
2ba86315 212 /* Show the widget and return. */
6b775dbb 213 return p;
2ba86315 214}
6cc5e1a6 215
2ba86315 216/* Plugin destructor. */
6b775dbb 217static void wincmd_destructor(gpointer user_data)
2ba86315 218{
6b775dbb 219 WinCmdPlugin * wc = user_data;
2ba86315
DB
220 g_free(wc->image);
221 g_free(wc);
222}
6cc5e1a6 223
2ba86315 224/* Callback when the configuration dialog has recorded a configuration change. */
6b775dbb 225static gboolean wincmd_apply_configuration(gpointer user_data)
2ba86315 226{
6b775dbb
AG
227 GtkWidget * p = user_data;
228 WinCmdPlugin * wc = lxpanel_plugin_get_data(p);
229
f7ecd6ce 230 //lxpanel_button_set_icon(p, wc->image, -1);
6b775dbb 231 /* Just save settings */
f7ecd6ce 232 //config_group_set_string(wc->settings, "image", wc->image);
6b775dbb
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);
238 return FALSE;
6cc5e1a6
DB
239}
240
2ba86315 241/* Callback when the configuration dialog is to be shown. */
6b775dbb 242static GtkWidget *wincmd_configure(LXPanel *panel, GtkWidget *p)
6cc5e1a6 243{
6b775dbb
AG
244 WinCmdPlugin * wc = lxpanel_plugin_get_data(p);
245 return lxpanel_generic_config_dlg(_("Minimize All Windows"),
246 panel, wincmd_apply_configuration, p,
2ba86315 247 _("Alternately iconify/shade and raise"), &wc->toggle_preference, CONF_TYPE_BOOL,
6b775dbb 248 /* FIXME: configure buttons 1 and 2 */
2ba86315 249 NULL);
2ba86315
DB
250}
251
6cc5e1a6 252
2ba86315 253/* Plugin descriptor. */
6b775dbb
AG
254LXPanelPluginInit lxpanel_static_plugin_wincmd = {
255 .name = N_("Minimize All Windows"),
256 .description = N_("Sends commands to all desktop windows.\nSupported commands are 1) iconify and 2) shade"),
257
258 .new_instance = wincmd_constructor,
259 .config = wincmd_configure,
6b775dbb 260 .button_press_event = wincmd_button_clicked
6cc5e1a6 261};